protected function hexdump($indent = 0) { $width = 32; $out = ''; $rows = ceil(strlen($this->data) / $width); $hd = new Hexdumper(); for ($i = 0; $i < $rows; $i++) { $row = substr($this->data, $i * $width, $width); $out .= $hd->hexdump($row, $indent, $width); } return $out; }
protected function write($datum, array &$context, &$acc, $type, $dest) { $output_mode = false; if ($dest == '_') { $to = ' -> ACC'; $dest =& $acc; } elseif ($dest == '!') { $to = ' -> OUT'; $dest = ''; $output_mode = true; } else { $to = ' -> ' . $dest; $dest =& $context[$dest]; } switch ($type) { case 'r': // raw $dest = $datum; break; case 's': // string $dest = (string) $this->unpackstr($datum); break; case 'i': // int $dest = (int) $this->unpacksint($datum); break; case 'u': // int $dest = (int) $this->unpackuint($datum); break; case 'h': // hexdump $hd = new Hexdumper(); $dest = trim($hd->hexdump($datum)); break; case 't': // timestamp -> date $dest = date("Y-m-d H:i:s", (int) $this->unpackuint($datum)); break; case 'f': // float $dest = (double) $this->unpackfloat($datum); break; default: throw new RuntimeException("Unknown type '{$type}'."); } if ($output_mode) { if ($dest === '') { $this->flushBuffer(); } else { $this->out_buffer .= $dest; } } // echo "$dest $to\n"; }
public function parseFromFile($fp) { // It looks like newer Serato sometimes allocates large chunks of free space in the file at the end. // This doesn't count as data, so we skip it, using str_pad() to make sure we also skip any run of // nulls that is shorter than 8 bytes. do { $header_bin = fread($fp, 8); if ($header_bin === false) { throw new RuntimeException("Read error; failed to read 8 bytes of chunk header"); } $length_read = strlen($header_bin); if ($length_read == 0) { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Reached EOF; no more to read", array()); return false; // if we read an exact chunk, it's not an 'eof'. } $just_blank_bytes = str_pad($header_bin, 8, "") == ""; if ($just_blank_bytes) { L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, "Hit unallocated blank space in file.", array()); // argh. Attempt to resync the stream to the next oent. // it looks like Serato sometimes has junk after the free space! if (!$this->resync($fp)) { // eof. return false; } } } while ($just_blank_bytes); if ($length_read < 8) { throw new OutOfBoundsException("No more data (read {$length_read} bytes)"); } list($chunk_type, $chunk_size) = $this->parseHeader($header_bin); if ($chunk_size > 1048576) { // a chunk larger than 1Mb!? $chunk_size = number_format($chunk_size / 1024 / 1024, 2); $dumper = new Hexdumper(); throw new RuntimeException(sprintf("Found chunk claiming to be enormous ({$chunk_size} MiB); are you reading the right file?\n%s", $dumper->hexdump($header_bin))); } if ($chunk_size > 0) { $body_bin = fread($fp, $chunk_size); $chunk = $this->chunk_factory->newChunk($chunk_type, $body_bin); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Read %s chunk from file (size: %d)", array($chunk_type, $chunk_size)); } else { $chunk = ''; L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, "Read 0-byte %s chunk from file. This is unusual.", array($chunk_type)); } return $chunk; }