Exemplo n.º 1
0
def _get_offset_endian_jpeg(f):
    ## it's a JPEG file
    logger.debug("JPEG format recognized data[0:2] == '0xFFD8'.")

    ## Determine the "base" from which to start reading
    f.seek(0)
    data = bytearray(f.read(12))
    base = 2
    while data[2] == 0xFF and data[6:10] in ('JFIF', 'JFXX', 'OLYM', 'Phot'):
        logger.debug("  data[2] == 0xFF data[3] == {:x} and data[6:10] = {}"
                     "".format(data[3], data[6:10]))
        length = (data[4] * 256) + data[5]
        assert isinstance(length, int)
        logger.debug("    Length offset is {:d}".format(length))
        f.read(length - 8)
        ## Fake an EXIF beginning of file
        ## I don't think this is used. --gd
        data = '\xFF\x00' + f.read(10)
        #fake_exif = 1
        if base > 2:
            base += length + 2
        else:
            base = length + 4
        logger.debug("    Set segment base to {}".format(base))

    del data  # We're done with it!!

    b = mmapbytes(f)
    while True:
        logger.debug("Segment base 0x{:X}".format(base))
        b.set_window(base)
        b1 = b[1]
        if b[0] == 0xFF:
            if b1 == 0xE1:
                if b[4:8] == "Exif":
                    base -= 2
                break
            if b1 == 0xDB:
                break
        _base_increment = (b[2] * 256) + b[3] + 2
        logger.debug("Increment base by {}".format(_base_increment))
        base += _base_increment

    ## Jump ahead after file headers
    b.set_window(base)
    _data_b2 = b[2]
    _data_b6t10 = b[6:10]
    _data_b6t11 = b[6:11]

    if _data_b2 == 0xFF:

        logger.debug("Exif header: {:x} {!r}".format(_data_b2, _data_b6t11))

        if _data_b6t10 == 'Exif':
            ## detected EXIF header
            offset = f.tell()
            endian = f.read(1)
            return offset, endian
            #HACK TEST:  endian = 'M'

        elif _data_b6t11 == 'Ducky':
            ## detected Ducky header.
            logger.debug("EXIF-like header (normally 0xFF and code): "
                         "{:x} and {!r}".format(_data_b2, _data_b6t11))
            offset = f.tell()
            endian = f.read(1)
            return offset, endian

        elif _data_b6t11 == 'Adobe':
            ## detected APP14 (Adobe)
            logger.debug("EXIF-like header (normally 0xFF and code): "
                         "{:x} and {!r}".format(_data_b2, _data_b6t11))
            offset = f.tell()
            endian = f.read(1)
            return offset, endian
    else:
        ## No EXIF information found -- error!!
        logger.debug(
            "No EXIF header found:\n"
            "    Expected b[2]==0xFF and b[6:10]=='Exif'' (or 'Duck')\n"
            "    Got: {:x} and {!r}".format(_data_b2, _data_b6t11))
        raise NoExifData("No EXIF header found")
Exemplo n.º 2
0
    def test_mmapbytes(self):
        from StringIO import StringIO
        from exifpy.utils import mmapbytes

        message = "Hello, world; spam & eggs for everybody!"

        ## Test direct referencing of items
        ## The object should behave exactly like a bytearray

        test_indices = [0, 7, 14, -1, -10, -14]
        test_windows = [
            (None, None),
            (0, 0),
            (0, 12),
            (None, 12),
            # (14, 0),  ## Invalid!!
            (14, None),
            (14, 25),
        ]

        for winStart, winEnd in test_windows:
            _message = message[winStart:winEnd]
            mm = mmapbytes(StringIO(message), winStart, winEnd)
            for idx in test_indices:
                try:
                    expected = ord(_message[idx])

                except IndexError:
                    # print "\n\n\nWe're running with window {},{}" \
                    #       "".format(winStart, winEnd)
                    # print "The string {!r} raised IndexError on index {}. "\
                    #     "We expect the mmapbytes() object to do the same."\
                    #     "".format(_message, idx)

                    with self.assertRaises(IndexError):
                        mm[idx]
                        # print "RETURNED {!r}".format(mm[idx])

                else:
                    result = mm[idx]
                    self.assertEqual(
                        expected,
                        result,
                        "Test window {},{} index {} - Expected: {!r} got: {!r}"
                        "".format(winStart, winEnd, idx, expected, result),
                    )

        ## Test some slicing.
        ## The object should behave exactly like a string.

        test_indices = [(0, 1), (0, 10), (0, None), (None, 0), (None, 10), (10, None), (None, None)]
        test_windows = [
            (None, None),
            (0, 0),
            (0, 12),
            (None, 12),
            # (14, 0),  # Invalid!
            (14, None),
            (14, 25),
        ]

        for winStart, winEnd in test_windows:
            _message = message[winStart:winEnd]
            mm = mmapbytes(StringIO(message), winStart, winEnd)
            for start, end in test_indices:
                expected = _message[start:end]
                result = mm[start:end]
                self.assertEqual(
                    expected,
                    result,
                    "Test window {},{} slice {},{} - Expected: {!r} got: {!r}"
                    "".format(winStart, winEnd, start, end, expected, result),
                )