def read(cls, fp): """Read the element from a file-like object. :param fp: file-like object """ name = read_unicode_string(fp) classID = read_length_and_key(fp) value = read_unicode_string(fp) return cls(name, classID, value)
def _decode_version_info(data): fp = io.BytesIO(data) return VersionInfo( read_fmt("I", fp)[0], read_fmt("?", fp)[0], read_unicode_string(fp), read_unicode_string(fp), read_fmt("I", fp)[0], )
def decode(data): """ Reads and decodes info about linked layers. These are embedded files (embedded smart objects). But Adobe calls them "linked layers", so we'll follow that nomenclature. Note that non-embedded smart objects are not included here. """ fp = io.BytesIO(data) layers = [] while True: start = fp.tell() length_buf = fp.read(8) if not length_buf: break # end of file length = struct.unpack(str('>Q'), length_buf)[0] liFD, version = read_fmt('4s I', fp) if liFD != b'liFD': warnings.warn('unknown layer type') break unique_id = read_pascal_string(fp, 'ascii') filename = read_unicode_string(fp) filetype, creator, filelength, have_file_open_descriptor = read_fmt('4s 4s Q B', fp) filetype = str(filetype) if have_file_open_descriptor: # Does not seem to contain any useful information undocumented_integer = read_fmt("I", fp) file_open_descriptor = decode_descriptor(None, fp) else: file_open_descriptor = None decoded = fp.read(filelength) # Undocumented extra field if version == 5: uuid = read_unicode_string(fp) else: uuid = None layers.append( LinkedLayer(version, unique_id, filename, filetype, file_open_descriptor, creator, decoded, uuid) ) # Gobble up anything that we don't know how to decode expected_position = start + 8 + length # first 8 bytes contained the length if expected_position != fp.tell(): warnings.warn('skipping over undocumented additional fields') fp.read(expected_position - fp.tell()) # Each layer is padded to start and end at 4-byte boundary pad = -fp.tell() % 4 fp.read(pad) return LinkedLayerCollection(layers)
def decode(data): """ Reads and decodes info about linked layers. These are embedded files (embedded smart objects). But Adobe calls them "linked layers", so we'll follow that nomenclature. Note that non-embedded smart objects are not included here. """ fp = io.BytesIO(data) layers = [] while True: start = fp.tell() length_buf = fp.read(8) if not length_buf: break # end of file length = struct.unpack(str('>Q'), length_buf)[0] liFD, version = read_fmt('4s I', fp) if liFD != b'liFD': warnings.warn('unknown layer type') break unique_id = read_pascal_string(fp, 'ascii') filename = read_unicode_string(fp) filetype, creator, filelength, have_file_open_descriptor = read_fmt( '4s 4s Q B', fp) filetype = str(filetype) if have_file_open_descriptor: # Does not seem to contain any useful information undocumented_integer = read_fmt("I", fp) file_open_descriptor = decode_descriptor(None, fp) else: file_open_descriptor = None decoded = fp.read(filelength) # Undocumented extra field if version == 5: uuid = read_unicode_string(fp) else: uuid = None layers.append( LinkedLayer(version, unique_id, filename, filetype, file_open_descriptor, creator, decoded, uuid)) # Gobble up anything that we don't know how to decode expected_position = start + 8 + length # first 8 bytes contained the length if expected_position != fp.tell(): warnings.warn('skipping over undocumented additional fields') fp.read(expected_position - fp.tell()) # Each layer is padded to start and end at 4-byte boundary pad = -fp.tell() % 4 fp.read(pad) return LinkedLayerCollection(layers)
def decode_descriptor(_, fp): name = read_unicode_string(fp)[:-1] classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) items = [] item_count = read_fmt("I", fp)[0] while len(items) < item_count: item_length = read_fmt("I", fp)[0] key = fp.read(item_length or 4) ostype = fp.read(4) decode_ostype = get_ostype_decode_func(ostype) if not decode_ostype: # For some reason, name can appear in the middle of items... if key == ReferenceOSType.NAME: fp.seek(fp.tell() - 4) name = decode_name(key, fp) continue raise UnknownOSType('Unknown descriptor item of type %r' % ostype) value = decode_ostype(key, fp) if value is None: warnings.warn("%r (%r) is None" % (key, ostype)) items.append((key, value)) return Descriptor(name, classID, items)
def decode_prop(key, fp): name = read_unicode_string(fp)[:-1] classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) keyID_length = read_fmt("I", fp)[0] keyID = fp.read(keyID_length or 4) return Property(name, classID, keyID)
def _decode_gradient_settings(data, **kwargs): fp = io.BytesIO(data) version, is_reversed, is_dithered = read_fmt("H 2B", fp) if version != 1: warnings.warn("Invalid Gradient settings version %s" % (version)) return data name = read_unicode_string(fp) color_count = read_fmt("H", fp)[0] color_stops = [] for i in range(color_count): location, midpoint, mode = read_fmt("2i H", fp) color = read_fmt("4H", fp) color_stops.append(ColorStop(location, midpoint, mode, color)) read_fmt("H", fp) # Undocumented pad. transparency_count = read_fmt("H", fp)[0] transparency_stops = [] for i in range(transparency_count): transparency_stops.append(read_fmt("2I H", fp)) expansion, interpolation, length, mode = read_fmt("4H", fp) if expansion != 2 or length != 32: warnings.warn("Ignoring Gradient settings") return data random_seed, show_transparency, use_vector_color = read_fmt("I 2H", fp) roughness, color_model = read_fmt("I H", fp) minimum_color = read_fmt("4H", fp) maximum_color = read_fmt("4H", fp) read_fmt("H", fp) # Dummy pad. return GradientSettings(version, is_reversed, is_dithered, name, color_stops, transparency_stops, expansion, interpolation, length, mode, random_seed, show_transparency, use_vector_color, roughness, color_model, minimum_color, maximum_color)
def test_unicode_string_wr(fixture, padding): with io.BytesIO() as f: write_unicode_string(f, fixture, padding=padding) data = f.getvalue() with io.BytesIO(data) as f: output = read_unicode_string(f, padding=padding) assert fixture == output
def read(cls, fp, **kwargs): kind = LinkedLayerType(read_fmt('4s', fp)[0]) version = read_fmt('I', fp)[0] assert 1 <= version and version <= 7, 'Invalid version %d' % (version) uuid = read_pascal_string(fp, 'macroman', padding=1) filename = read_unicode_string(fp) filetype, creator, datasize, open_file = read_fmt('4s4sQB', fp) if open_file: open_file = DescriptorBlock.read(fp, padding=1) else: open_file = None linked_file = None timestamp = None data = None filesize = None child_id = None mod_time = None lock_state = None if kind == LinkedLayerType.EXTERNAL: linked_file = DescriptorBlock.read(fp, padding=1) if version > 3: timestamp = read_fmt('I4Bd', fp) filesize = read_fmt('Q', fp)[0] # External file size. if version > 2: data = fp.read(datasize) elif kind == LinkedLayerType.ALIAS: read_fmt('8x', fp) if kind == LinkedLayerType.DATA: data = fp.read(datasize) assert len(data) == datasize, '(%d vs %d)' % (len(data), datasize) # The followings are not well documented... if version >= 5: child_id = read_unicode_string(fp) if version >= 6: mod_time = read_fmt('d', fp)[0] if version >= 7: lock_state = read_fmt('B', fp)[0] if kind == LinkedLayerType.EXTERNAL and version == 2: data = fp.read(datasize) return cls(kind, version, uuid, filename, filetype, creator, filesize, open_file, linked_file, timestamp, data, child_id, mod_time, lock_state)
def read(cls, fp): """Read the element from a file-like object. :param fp: file-like object """ name = read_unicode_string(fp) classID = read_length_and_key(fp) offset = read_fmt('I', fp)[0] return cls(name, classID, offset)
def decode_enum_ref(key, fp): name = read_unicode_string(fp)[:-1] classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) typeID_length = read_fmt("I", fp)[0] typeID = fp.read(typeID_length or 4) enum_length = read_fmt("I", fp)[0] enum = fp.read(enum_length or 4) return EnumReference(name, classID, typeID, enum)
def _decode_slices_v6(fp): bbox = read_fmt('4I', fp) name = read_unicode_string(fp) count = read_fmt('I', fp)[0] items = [] for index in range(count): items.append(_decode_slices_v6_block(fp)) return SlicesHeaderV6(bbox[0], bbox[1], bbox[2], bbox[3], name, count, items)
def decode_descriptor(data): fp = io.BytesIO(data) name = read_unicode_string(fp) classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) item_count = read_fmt("I", fp)[0] items = fp.read() # TODO: detailed parsing return Descriptor(name, classID, item_count, items)
def test_unicode_stringrw(fixture, padding): with io.BytesIO(fixture) as f: data = read_unicode_string(f, padding=padding) print(len(fixture), f.tell()) print('%d %r' % (len(data), data)) with io.BytesIO() as f: write_unicode_string(f, data, padding=padding) output = f.getvalue() assert fixture == output
def read(cls, fp): slice_id, group_id, origin = read_fmt('3I', fp) associated_id = read_fmt('I', fp)[0] if origin == 1 else None name = read_unicode_string(fp) slice_type = read_fmt('I', fp)[0] bbox = read_fmt('4I', fp) url = read_unicode_string(fp) target = read_unicode_string(fp) message = read_unicode_string(fp) alt_tag = read_unicode_string(fp) cell_is_html = read_fmt('?', fp)[0] cell_text = read_unicode_string(fp) horizontal_align, vertical_align = read_fmt('2I', fp) alpha, red, green, blue = read_fmt('4B', fp) data = None if is_readable(fp, 4): # There is no easy distinction between descriptor block and # next slice v6 item here... current_position = fp.tell() version = read_fmt('I', fp)[0] fp.seek(-4, 1) if version == 16: try: data = DescriptorBlock.read(fp) if data.classID == b'\x00\x00\x00\x00': data = None raise ValueError(data) except ValueError: logger.debug('Failed to read DescriptorBlock') fp.seek(current_position) return cls(slice_id, group_id, origin, associated_id, name, slice_type, bbox, url, target, message, alt_tag, cell_is_html, cell_text, horizontal_align, vertical_align, alpha, red, green, blue, data)
def _read_body(cls, fp): name = read_unicode_string(fp, padding=1) classID = read_length_and_key(fp) items = [] count = read_fmt('I', fp)[0] for _ in range(count): key = read_length_and_key(fp) ostype = OSType(fp.read(4)) kls = TYPES.get(ostype) value = kls.read(fp) items.append((key, value)) return dict(name=name, classID=classID, items=items)
def _decode_url_list(data): urls = [] fp = io.BytesIO(data) count = read_fmt("I", fp)[0] try: for i in range(count): number, id = read_fmt("2I", fp) url = read_unicode_string(fp) urls.append(UrlListItem(number, id, url)) return urls except UnknownOSType as e: warnings.warn("Ignoring image resource %s" % e) return data
def read(cls, fp, **kwargs): version = read_fmt('I', fp)[0] assert version == 1, 'Invalid version %d' % (version) image_mode = ColorMode(read_fmt('I', fp)[0]) point = read_fmt('2h', fp) name = read_unicode_string(fp) pattern_id = read_pascal_string(fp, encoding='ascii', padding=1) color_table = None if image_mode == ColorMode.INDEXED: color_table = [read_fmt("3B", fp) for i in range(256)] read_fmt('4x', fp) data = VirtualMemoryArrayList.read(fp) return cls(version, image_mode, point, name, pattern_id, color_table, data)
def _decode_pattern(data): fp = io.BytesIO(data) version, image_mode = read_fmt("2I", fp) if version != 1: warnings.warn("Unsupported patterns version %s" % (version)) return data point = read_fmt("2h", fp) name = read_unicode_string(fp) pattern_id = read_pascal_string(fp, 'ascii') color_table = None if image_mode == ColorMode.INDEXED: color_table = [read_fmt("3B", fp) for i in range(256)] read_fmt('4B', fp) # Undocumented field here... vma_list = _decode_virtual_memory_array_list(fp) return Pattern(version, image_mode, point, name, pattern_id, color_table, vma_list)
def read(cls, fp, **kwargs): version, is_reversed, is_dithered = read_fmt('H2B', fp) assert version == 1, 'Invalid version %s' % (version) name = read_unicode_string(fp) count = read_fmt('H', fp)[0] color_stops = [ColorStop.read(fp) for _ in range(count)] count = read_fmt('H', fp)[0] transparency_stops = [TransparencyStop.read(fp) for _ in range(count)] expansion, interpolation, length, mode = read_fmt('4H', fp) assert expansion == 2, 'Invalid expansion %d' % (expansion) random_seed, show_transparency, use_vector_color = read_fmt('I2H', fp) roughness, color_model = read_fmt('IH', fp) minimum_color = read_fmt('4H', fp) maximum_color = read_fmt('4H', fp) read_fmt('2x', fp) # Dummy? return cls(version, is_reversed, is_dithered, name, color_stops, transparency_stops, expansion, interpolation, length, mode, random_seed, show_transparency, use_vector_color, roughness, color_model, minimum_color, maximum_color)
def decode_descriptor(fp): name = read_unicode_string(fp) classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) items = [] item_count = read_fmt("I", fp)[0] for n in range(item_count): item_length = read_fmt("I", fp)[0] key = fp.read(item_length or 4) ostype = fp.read(4) decode_ostype = get_ostype(ostype) if decode_ostype: value = decode_ostype(key, fp) if value is not None: items.append((key.decode(), value)) return Descriptor(name, classID, items)
def decode_descriptor(_, fp): name = read_unicode_string(fp)[:-1] classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) items = [] item_count = read_fmt("I", fp)[0] for n in range(item_count): item_length = read_fmt("I", fp)[0] key = fp.read(item_length or 4) ostype = fp.read(4) decode_ostype = get_ostype_decode_func(ostype) if not decode_ostype: raise UnknownOSType('Unknown descriptor item of type %r' % ostype) value = decode_ostype(key, fp) if value is not None: items.append((key, value)) return Descriptor(name, classID, items)
def decode_descriptor(_, fp): name = read_unicode_string(fp)[:-1] classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) items = [] item_count = read_fmt("I", fp)[0] for n in range(item_count): item_length = read_fmt("I", fp)[0] key = fp.read(item_length or 4) ostype = fp.read(4) decode_ostype = get_ostype_decode_func(ostype) if not decode_ostype: raise UnknownOSType("Unknown descriptor item of type %r" % ostype) value = decode_ostype(key, fp) if value is not None: items.append((key, value)) return Descriptor(name, classID, items)
def decode_pattern(patternData): #print("decode pattern",somehint) # repeated for each pattern patterns = [] endOfPatterns = len(patternData) if endOfPatterns == 0: return patterns print("end of pattern", endOfPatterns) fp = io.BytesIO(patternData) #image mode Bitmap = 0; Grayscale = 1; Indexed = 2; RGB = 3; CMYK = 4; Multichannel = 7; Duotone = 8; Lab = 9 patternLength = read_fmt("I", fp)[0] while patternLength != 0: start = fp.tell() version, imageMode = read_fmt("II", fp) h, w = read_fmt("hh", fp) name = read_unicode_string(fp) unique_id = read_pascal_string(fp, 'ascii') print("decoding pattern", patternLength, version, imageMode, w, h, name, unique_id) data = decode_virtual_memory_array_list(fp, w, h) # seek to expected ending of pattern fp.seek(start + patternLength) if fp.tell() <= endOfPatterns - 4: patternLength = read_fmt("I", fp)[0] else: patternLength = 0 print("pattern pos ", fp.tell(), "expected", start + patternLength, "end", endOfPatterns) patterns.append(Pattern(name, unique_id, data, w, h)) #mode = _get_mode(len(data)) return patterns
def _decode_slices_v6_block(fp): slice_id, group_id, origin = read_fmt('3I', fp) associated_id = read_fmt('I', fp)[0] if origin == 1 else None name = read_unicode_string(fp) slice_type, left, top, right, bottom = read_fmt('5I', fp) url = read_unicode_string(fp) target = read_unicode_string(fp) message = read_unicode_string(fp) alt_tag = read_unicode_string(fp) cell_is_html = read_fmt('?', fp)[0] cell_text = read_unicode_string(fp) horizontal_alignment, vertical_alignment = read_fmt('2I', fp) alpha, red, green, blue = read_fmt('4B', fp) # Some version stores descriptor here, but the documentation unclear... descriptor = None return SlicesResourceBlock( slice_id, group_id, origin, associated_id, name, slice_type, left, top, right, bottom, url, target, message, alt_tag, cell_is_html, cell_text, horizontal_alignment, vertical_alignment, alpha, red, green, blue, descriptor)
def decode_class(key, fp): name = read_unicode_string(fp)[:-1] classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) return Class(name, classID)
def read(cls, fp, padding=1, **kwargs): return cls(read_unicode_string(fp, padding=padding))
def unicode_string(data): return read_unicode_string(io.BytesIO(data))
def decode_string(key, fp): value = read_unicode_string(fp)[:-1] return String(value)
def decode_offset(key, fp): name = read_unicode_string(fp)[:-1] classID_length = read_fmt("I", fp)[0] classID = fp.read(classID_length or 4) offset = read_fmt("I", fp)[0] return Offset(name, classID, offset)
def read(cls, fp): name = read_unicode_string(fp) classID = read_length_and_key(fp) value = read_unicode_string(fp) return cls(name, classID, value)
def read(cls, fp): name = read_unicode_string(fp) classID = read_length_and_key(fp) offset = read_fmt('I', fp)[0] return cls(name, classID, offset)
def read(cls, fp): name = read_unicode_string(fp) classID = read_length_and_key(fp) typeID = read_length_and_key(fp) enum = read_length_and_key(fp) return cls(name, classID, typeID, enum)
def decode_name(key, fp): value = read_unicode_string(fp)[:-1] return Name(value)
def _decode_alpha_names_unicode(data): fp = io.BytesIO(data) return read_unicode_string(fp)[:-1]