From c11dad792c884e7f55331ddf9a683bc7932ef6a5 Mon Sep 17 00:00:00 2001 From: GRiker Date: Wed, 10 Mar 2010 04:56:37 -0700 Subject: [PATCH 1/3] GwR paranoia about '@' preceding dkey --- src/calibre/ebooks/metadata/topaz.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/metadata/topaz.py b/src/calibre/ebooks/metadata/topaz.py index bed982011d..d7bbff0f7f 100644 --- a/src/calibre/ebooks/metadata/topaz.py +++ b/src/calibre/ebooks/metadata/topaz.py @@ -201,7 +201,8 @@ class MetadataUpdater(object): break dkey = self.topaz_headers[x] dks = StringIO.StringIO() - dks.write('d@') + dks.write(self.eod) + dks.write(self.base_value) dks.write(self.encode_vwi(len(dkey['tag']))) offset += 1 dks.write(dkey['tag']) @@ -263,9 +264,10 @@ class MetadataUpdater(object): topaz_headers[x] = dict(tag=tag,blocks=blocks) self.topaz_headers = topaz_headers - eod = self.data[offset] + self.eod = self.data[offset] offset += 1 self.base = offset + self.base_value = self.data[offset] return md_header_offset, topaz_headers From 5aaee8698337f8dca50bd0685dd13ef12c9a8345 Mon Sep 17 00:00:00 2001 From: GRiker Date: Wed, 10 Mar 2010 07:07:59 -0700 Subject: [PATCH 2/3] GwR change seek for second instance of 'metadata' in file if > 8096, variable length pad before dkey --- src/calibre/ebooks/metadata/topaz.py | 43 +++++++++++++++++++--------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/calibre/ebooks/metadata/topaz.py b/src/calibre/ebooks/metadata/topaz.py index d7bbff0f7f..7ba847d4a3 100644 --- a/src/calibre/ebooks/metadata/topaz.py +++ b/src/calibre/ebooks/metadata/topaz.py @@ -115,12 +115,19 @@ class MetadataUpdater(object): first = raw.find('metadata') if first < 0: raise ValueError('Invalid Topaz file') - second = raw.find('metadata', first+10) - if second < 0: - raise ValueError('Invalid Topaz file') - self.md_start = second-1 + self.data = StreamSlicer(stream) self.header_records, = unpack('>B',self.data[4]) + self.get_topaz_headers() + + # Seek the metadata block + md_block_offset, spam = self.decode_vwi(self.data[first+9:first+13]) + md_block_offset += self.base + if self.data[md_block_offset+1:md_block_offset+9] != 'metadata': + raise ValueError('Invalid Topaz file') + else: + self.md_start = md_block_offset + offset = self.get_md_header(self.md_start) self.metadata = {} self.md_end = self.get_original_metadata(offset) @@ -195,14 +202,16 @@ class MetadataUpdater(object): def generate_dkey(self): for x in self.topaz_headers: + #print "dkey['blocks']: %s" % self.topaz_headers[x]['blocks'] if self.topaz_headers[x]['tag'] == 'dkey': - offset = self.base + self.topaz_headers[x]['blocks'][0]['hdr_offset'] - len_uncomp = self.topaz_headers[x]['blocks'][0]['len_uncomp'] - break + if self.topaz_headers[x]['blocks']: + offset = self.base + self.topaz_headers[x]['blocks'][0]['hdr_offset'] + len_uncomp = self.topaz_headers[x]['blocks'][0]['len_uncomp'] + break + else: + return None dkey = self.topaz_headers[x] dks = StringIO.StringIO() - dks.write(self.eod) - dks.write(self.base_value) dks.write(self.encode_vwi(len(dkey['tag']))) offset += 1 dks.write(dkey['tag']) @@ -243,6 +252,7 @@ class MetadataUpdater(object): offset = 5 topaz_headers = {} + dkey_offset = 0 for x in range(self.header_records): marker = self.data[offset] offset += 1 @@ -255,6 +265,8 @@ class MetadataUpdater(object): blocks = {} for val in range(num_vals): hdr_offset, consumed = self.decode_vwi(self.data[offset:offset+4]) + if tag == 'dkey': + dkey_offset = hdr_offset offset += consumed len_uncomp, consumed = self.decode_vwi(self.data[offset:offset+4]) offset += consumed @@ -267,7 +279,9 @@ class MetadataUpdater(object): self.eod = self.data[offset] offset += 1 self.base = offset - self.base_value = self.data[offset] + self.base_value = None + if dkey_offset: + self.base_value = self.data[offset:offset + dkey_offset] return md_header_offset, topaz_headers @@ -334,8 +348,6 @@ class MetadataUpdater(object): self.metadata[item]['metadata'] = value return - self.get_topaz_headers() - try: from calibre.ebooks.conversion.config import load_defaults prefs = load_defaults('mobi_output') @@ -359,9 +371,14 @@ class MetadataUpdater(object): self.stream.seek(0) self.stream.truncate(0) self.stream.write(head) - self.stream.write(dkey) + self.stream.write(self.eod) + if self.base_value: + self.stream.write(self.base_value) + if dkey: + self.stream.write(dkey) self.stream.write(updated_metadata) self.stream.write(tail) + self.stream.close() def set_metadata(stream, mi): mu = MetadataUpdater(stream) From 834fd93bc85cfb3fa243f26edff81f2bd3919337 Mon Sep 17 00:00:00 2001 From: GRiker Date: Wed, 10 Mar 2010 07:31:34 -0700 Subject: [PATCH 3/3] GwR bail if metadata sequence out of order --- src/calibre/ebooks/metadata/topaz.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/metadata/topaz.py b/src/calibre/ebooks/metadata/topaz.py index 7ba847d4a3..4f442a844f 100644 --- a/src/calibre/ebooks/metadata/topaz.py +++ b/src/calibre/ebooks/metadata/topaz.py @@ -253,6 +253,7 @@ class MetadataUpdater(object): offset = 5 topaz_headers = {} dkey_offset = 0 + highest_payload_offset = 0 for x in range(self.header_records): marker = self.data[offset] offset += 1 @@ -267,6 +268,10 @@ class MetadataUpdater(object): hdr_offset, consumed = self.decode_vwi(self.data[offset:offset+4]) if tag == 'dkey': dkey_offset = hdr_offset + if tag != 'metadata': + if hdr_offset > highest_payload_offset: + highest_payload_offset = hdr_offset + #print "adjusting highest_payload_offset to 0x%x (%s)" % (hdr_offset,tag) offset += consumed len_uncomp, consumed = self.decode_vwi(self.data[offset:offset+4]) offset += consumed @@ -275,14 +280,13 @@ class MetadataUpdater(object): blocks[val] = dict(hdr_offset=hdr_offset,len_uncomp=len_uncomp,len_comp=len_comp) topaz_headers[x] = dict(tag=tag,blocks=blocks) self.topaz_headers = topaz_headers - + self.highest_payload_offset = highest_payload_offset self.eod = self.data[offset] offset += 1 self.base = offset self.base_value = None if dkey_offset: self.base_value = self.data[offset:offset + dkey_offset] - return md_header_offset, topaz_headers def generate_metadata_stream(self): @@ -348,6 +352,9 @@ class MetadataUpdater(object): self.metadata[item]['metadata'] = value return + if self.md_start > self.highest_payload_offset: + raise ValueError('Unable to update metadata') + try: from calibre.ebooks.conversion.config import load_defaults prefs = load_defaults('mobi_output') @@ -378,7 +385,7 @@ class MetadataUpdater(object): self.stream.write(dkey) self.stream.write(updated_metadata) self.stream.write(tail) - self.stream.close() + def set_metadata(stream, mi): mu = MetadataUpdater(stream)