0

i am a hobby php-dev and have the following problem:

i have a rar-file, whose header is damaged, therefor extracting is not fully possible. the contents are non-compressed, and can be read with eg. a hex-editor. the archive contains jpeg-files, but because of the damaged header, some of them are not extractable in winrar. i have tried repairing, but a good portion of the file remains broken.

i want to read the file in, and look for the bytes that indicate start and end of a jpeg (from what i know they are FFD8FF for start and FFD9FF for end). using a hex-editor i have managed to find some of those bytes, and also extracting the image into a file and view it does work. since the file is 500mb, i want to do this automatically, and since i am php-friendly, i would like to do it there :-)

i know how to read a file bytewise (fread), what i am having difficulties is, parsing the file correctly in hex, so i can identify the starts and ends. what i am thinking about is something like this (in pseudocode):

while( READ FILE UNTIL EOF ){
    if( CURRENTBYTES == FFD8FF ){
        $jpeg_file = READ FILE UNTIL CURRENTBYTES == FFD9FF
        fwrite($jpeg_file, "xyz.jpg");
        // return to while, looking for next FFD8FF
    }
}

could someone give me a hint, how the reading and identifying would be done best? the main question is, how can i read a file until a start-byte, then save the following, then look for the next start-byte? efficiency, security, code beauty are no concern, i just want all the pics :-)

many thanx for any helps

  • Just a remark. While the SOI (start of image) marker is FF D8 and is always immediately followed by another marker whose first byte is always FF (thus giving the impression that FF D8 FF can be expected at the beginning), the EOI (end of image) marker is just FF D9, without another marker. Technically, the JPEG file ends with the D9 being the last byte. – rwong Sep 12 '15 at 12:23
  • There's no guarantee that FF D9 won't appear in the middle of the image data. You may need to parse the file a little more. – Dan Pichelman Sep 15 '15 at 20:13
1

Since efficiency is no concern, and 500mb is not that large anymore, the simplest option would be:

  • read the file into string $blob (hint: file_get_contents).
  • get each separate part into an array $parts. Ugly solution: preg_match_all('/\xff\xd8\xff(.*?)\xff\xd9\xff/', $blob, $matches), and inspect the shape of the list $matches afterwards.
  • safe each $part in a separate file, by for instance using the md5sum of the file as filename. (md5sum ought to be good enough for this)

This should be enough I suppose.

  • i am trying, but i keep running out of memory when i transform the binary file to hex (bin2hex) ... is there a way of doing this with a stream of some sort? i could split the file in parts, but then i risk cutting it inbetween a jpeg-file-area which results in probably loosing that one... apparently efficiency is somewhat of a concern :-) – benny.utzer Sep 12 '15 at 21:47
  • 1
    Then don't transform the file to hexadecimal first. The given regular expression in preg_match_all should work on the binary data. – Sjoerd Job Postmus Sep 13 '15 at 7:20
1

I would step through the file, instead of reading it all at once. Look for the first byte (0xFF), and when found, see if the next byte is 0xD8. If so, open output file and write those two bytes, followed by each byte until you reach the end pattern. Look for it the same way as the start bytes and close the file output when encountered.

Memory usage will be much less. If should run much faster than using a regex.

This is basically a very simple state machine.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.