Ejemplo n.º 1
0
    def parse(self):
        """ Parse the structure. """

        # The first four bytes of a data structure should always be the ASCII
        # string 8BIM
        data = self.read(4)
        if (data == "8BIM"):
            # The next two bytes specify the resource ID (tag number)
            tag_num_data = self.read(2)
            if (tag_num_data):
                tag_num = byteform.btousi(tag_num_data,
                                          big_endian=self.big_endian)

                # What then follows is the "Pascal string". The first byte determines its
                # length. If the total is an uneven number, it is padded with a \x00
                # character. We don't need this string, so we step over it.
                ps_len = byteform.btousi(self.read(1),
                                         big_endian=self.big_endian)
                if ((ps_len % 2) == 0):
                    ps_len += 1
                self.read(ps_len)

                # Now it's getting interesting; the next four bytes determine the length
                # of the data
                data_len = byteform.btousi(self.read(4),
                                           big_endian=self.big_endian)

                # Store the byte position and data length in the tags dict
                self.tags[tag_num] = datablock.DataBlock(
                    self.fp, self.byte_pos, data_len)

                # Skip to the next structure
                self.read(data_len)
Ejemplo n.º 2
0
    def parse(self):
        """ Parse the IPTC block. """

        # The IPTC data is structured in a very simple way; as a lineary stream of
        # tags and the associated data. Tags can belong to different segments, but
        # this segment number is simply written in front of each tag.

        #Each tag starts with the bye 0x1C
        try:
            start_byte = self.read(1)
        except IOError:
            start_byte = None

        while (start_byte == "\x1c"):
            # The next byte specifies the record number
            record_num = byteform.btousi(self.read(1))

            # Then follows the tag number
            tag_type = byteform.btousi(self.read(1))

            # The next two bytes determine the payload length, or the length of the
            # fields specifying the payload length if we have an extended tag.
            length = byteform.btousi(self.read(2), big_endian=self.big_endian)
            # If the most significant bit is 1, we have an extended tag
            if (length & 32768):  # 10000000 00000000
                # We have an extended tag
                length_count = length & 32767  # 01111111 11111111
                length = byteform.btousi(self.read(length_count),
                                         big_endian=self.big_endian)

            # Construct the tag and append it to the list
            tag_obj = datablock.DataBlock(self.fp,
                                          self.tell() + self.getDataOffset(),
                                          length)
            record = self.records.query("num", record_num, "record")
            if (tag_type in record.fields):
                record.fields[tag_type].append(tag_obj)
            else:
                record.fields[tag_type] = [tag_obj]

            # Seek to the next read position and read the new first byte
            self.seek(self.tell() + length)
            try:
                start_byte = self.read(1)
            except IOError:
                break

        self.parsed = True
Ejemplo n.º 3
0
    def __init__(self,
                 file_pointer=None,
                 ifd_offset=0,
                 header_offset=0,
                 data=None,
                 big_endian=True):
        # Create a temporary Datablock to parse the data
        block = datablock.DataBlock(fp=file_pointer,
                                    offset=ifd_offset,
                                    data=data)

        # Read the header string
        header = block.read(len(self.header_str))
        if (header != self.header_str) and (header != ""):
            raise "No valid Makernote!"

        # Read the rest of the header and save it for writing
        self.extra_bytes = block.read(self.header_length -
                                      len(self.header_string))

        # Initialize the IFD
        ifd.IFD.__init__(self, file_pointer, ifd_offset + self.header_length,
                         header_offset, data, big_endian)
Ejemplo n.º 4
0
    def __init__(self,
                 file_pointer=None,
                 ifd_offset=0,
                 header_offset=0,
                 data=None,
                 big_endian=False):
        # Fujifilm always uses little endian
        block = datablock.DataBlock(fp=file_pointer,
                                    offset=ifd_offset + header_offset,
                                    data=data)
        header = block.read(8)
        if (header == None):
            mn_offset = 0
        elif (header == "FUJIFILM"):
            mn_offset = byteform.btousi(block.read(4), big_endian=False)
        else:
            raise "No valid Fujifilm Makernote!"

        ifd.IFD.__init__(self,
                         file_pointer,
                         mn_offset,
                         ifd_offset + header_offset,
                         data,
                         big_endian=False)
Ejemplo n.º 5
0
    def __getTagObj__(self,
                      tag_num,
                      payload=None,
                      check=True,
                      data_type=None,
                      count=None,
                      data=None):
        """ Helper method to prepare a tag object for setTag and appendTag. """

        # Get the index and check if we can set this tag
        index = self.tags.query("num", tag_num)
        if (index is False):
            if (check):
                raise KeyError, "Tag %d is not known in this record!" % tag_num
            else:
                if not ((data_type) or (data)):
                    raise KeyError, "Unknown tag %d, and no further way to encode it" % tag_num

        # If the user wants to set the data herself, check if its of the correct
        # type
        if (data):
            if (type(data) != types.StringType):
                raise TypeError, "IPTC data should be a binary string"
        # Otherwise, encode it
        elif (payload):
            # Find out the data type for the tag num
            if (not data_type):
                data_type = self.tags.query(index, "data_type")

            # Retrieve the allowed lengths
            if (not count):
                count = self.tags.query(index, "count")
            if (type(count) == types.ListType):
                min_count, max_count = count
            else:
                min_count = count
                max_count = count

            # Check if the payload has enough data
            if (type(payload)
                    not in [types.ListType, types.TupleType,
                            types.StringType]):
                payload = [payload]
            if (
                (min_count) and (max_count)
            ):  # This might not be the case if we encode an unknown tag and the user didn't supply a count
                if ((len(payload) < min_count) or (len(payload) > max_count)):
                    raise "Wrong number of arguments supplied to encode tag %s!" % str(
                        tag_num)

            # Encode the data
            data = DATA_TYPES[data_type].encode(payload, self.big_endian)

            # If data type is Digits, pad it with zeroes
            if (data_type == 15):
                word_width = DATA_TYPES[data_type].word_width
                data = ((min_count * word_width) - len(data)) * "0" + data
        else:
            raise "Specify either a payload and optionally means to encode, or binary data"

        return datablock.DataBlock(data=data)
Ejemplo n.º 6
0
    def setTag(self, tag_num, data):
        """ Set the tag_num to data. """

        self.tags[tag_num] = datablock.DataBlock(data=data)