home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_927 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  23.9 KB  |  723 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
  6. import struct
  7. import zlib
  8. import sys
  9. import os
  10. from shutil import copyfileobj
  11. from cStringIO import StringIO
  12. import xml.dom.minidom as dom
  13. from functools import wraps
  14. from calibre.devices.prs500.prstypes import field
  15. from calibre.ebooks.metadata import MetaInformation, string_to_authors
  16. BYTE = '<B'
  17. WORD = '<H'
  18. DWORD = '<I'
  19. QWORD = '<Q'
  20.  
  21. class versioned_field(field):
  22.     
  23.     def __init__(self, vfield, version, start = 0, fmt = WORD):
  24.         field.__init__(self, start = start, fmt = fmt)
  25.         self.vfield = vfield
  26.         self.version = version
  27.  
  28.     
  29.     def enabled(self):
  30.         return self.vfield > self.version
  31.  
  32.     
  33.     def __get__(self, obj, typ = None):
  34.         if self.enabled():
  35.             return field.__get__(self, obj, typ = typ)
  36.         return None
  37.  
  38.     
  39.     def __set__(self, obj, val):
  40.         if not self.enabled():
  41.             raise LRFException('Trying to set disabled field')
  42.         self.enabled()
  43.         field.__set__(self, obj, val)
  44.  
  45.  
  46.  
  47. class LRFException(Exception):
  48.     pass
  49.  
  50.  
  51. class fixed_stringfield(object):
  52.     
  53.     def __init__(self, length = 8, start = 0):
  54.         self._length = length
  55.         self._start = start
  56.  
  57.     
  58.     def __get__(self, obj, typ = None):
  59.         length = str(self._length)
  60.         return obj.unpack(start = self._start, fmt = '<' + length + 's')[0]
  61.  
  62.     
  63.     def __set__(self, obj, val):
  64.         if val.__class__.__name__ != 'str':
  65.             val = str(val)
  66.         
  67.         if len(val) != self._length:
  68.             raise LRFException('Trying to set fixed_stringfield with a ' + 'string of  incorrect length')
  69.         len(val) != self._length
  70.         obj.pack(val, start = self._start, fmt = '<' + str(len(val)) + 's')
  71.  
  72.     
  73.     def __repr__(self):
  74.         return 'A string of length ' + str(self._length) + ' starting at byte ' + str(self._start)
  75.  
  76.  
  77.  
  78. class xml_attr_field(object):
  79.     
  80.     def __init__(self, tag_name, attr, parent = 'BookInfo'):
  81.         self.tag_name = tag_name
  82.         self.parent = parent
  83.         self.attr = attr
  84.  
  85.     
  86.     def __get__(self, obj, typ = None):
  87.         document = obj.info
  88.         elems = document.getElementsByTagName(self.tag_name)
  89.         if len(elems):
  90.             elem = None
  91.             for candidate in elems:
  92.                 if candidate.parentNode.nodeName == self.parent:
  93.                     elem = candidate
  94.                     continue
  95.             
  96.             if elem and elem.hasAttribute(self.attr):
  97.                 return elem.getAttribute(self.attr)
  98.         
  99.         return ''
  100.  
  101.     
  102.     def __set__(self, obj, val):
  103.         if val == None:
  104.             val = ''
  105.         
  106.         document = obj.info
  107.         elems = document.getElementsByTagName(self.tag_name)
  108.         if len(elems):
  109.             elem = None
  110.             for candidate in elems:
  111.                 if candidate.parentNode.nodeName == self.parent:
  112.                     elem = candidate
  113.                     continue
  114.             
  115.         
  116.         if elem:
  117.             elem.setAttribute(self.attr, val)
  118.         
  119.         obj.info = document
  120.  
  121.     
  122.     def __repr__(self):
  123.         return 'XML Attr Field: ' + self.tag_name + ' in ' + self.parent
  124.  
  125.     
  126.     def __str__(self):
  127.         return self.tag_name + '.' + self.attr
  128.  
  129.  
  130.  
  131. class xml_field(object):
  132.     
  133.     def __init__(self, tag_name, parent = 'BookInfo'):
  134.         self.tag_name = tag_name
  135.         self.parent = parent
  136.  
  137.     
  138.     def __get__(self, obj, typ = None):
  139.         document = obj.info
  140.         elems = document.getElementsByTagName(self.tag_name)
  141.         if len(elems):
  142.             elem = None
  143.             for candidate in elems:
  144.                 if candidate.parentNode.nodeName == self.parent:
  145.                     elem = candidate
  146.                     continue
  147.             
  148.             if elem:
  149.                 elem.normalize()
  150.                 if elem.hasChildNodes():
  151.                     return elem.firstChild.data.strip()
  152.             
  153.         
  154.         return ''
  155.  
  156.     
  157.     def __set__(self, obj, val):
  158.         if not val:
  159.             val = ''
  160.         
  161.         document = obj.info
  162.         
  163.         def create_elem():
  164.             elem = document.createElement(self.tag_name)
  165.             parent = document.getElementsByTagName(self.parent)[0]
  166.             parent.appendChild(elem)
  167.             return elem
  168.  
  169.         if not val:
  170.             val = u''
  171.         
  172.         if type(val).__name__ != 'unicode':
  173.             val = unicode(val, 'utf-8')
  174.         
  175.         elems = document.getElementsByTagName(self.tag_name)
  176.         elem = None
  177.         if len(elems):
  178.             for candidate in elems:
  179.                 if candidate.parentNode.nodeName == self.parent:
  180.                     elem = candidate
  181.                     continue
  182.             
  183.             if not elem:
  184.                 elem = create_elem()
  185.             else:
  186.                 elem.normalize()
  187.                 while elem.hasChildNodes():
  188.                     elem.removeChild(elem.lastChild)
  189.         else:
  190.             elem = create_elem()
  191.         elem.appendChild(document.createTextNode(val))
  192.         obj.info = document
  193.  
  194.     
  195.     def __str__(self):
  196.         return self.tag_name
  197.  
  198.     
  199.     def __repr__(self):
  200.         return 'XML Field: ' + self.tag_name + ' in ' + self.parent
  201.  
  202.  
  203.  
  204. def insert_into_file(fileobj, data, start, end):
  205.     buffer = StringIO()
  206.     fileobj.seek(end)
  207.     copyfileobj(fileobj, buffer, -1)
  208.     buffer.flush()
  209.     buffer.seek(0)
  210.     fileobj.seek(start)
  211.     fileobj.write(data)
  212.     fileobj.flush()
  213.     fileobj.truncate()
  214.     delta = fileobj.tell() - end
  215.     copyfileobj(buffer, fileobj, -1)
  216.     fileobj.flush()
  217.     buffer.close()
  218.     return delta
  219.  
  220.  
  221. def get_metadata(stream):
  222.     lrf = None if isinstance(stream, LRFMetaFile) else LRFMetaFile(stream)
  223.     authors = string_to_authors(lrf.author)
  224.     mi = MetaInformation(lrf.title.strip(), authors)
  225.     mi.author = lrf.author.strip()
  226.     mi.comments = lrf.free_text.strip()
  227.     mi.category = lrf.category.strip() + ', ' + lrf.classification.strip()
  228.     tags = _[1]
  229.     if mi.category.strip() == ',':
  230.         mi.category = None
  231.     
  232.     mi.publisher = lrf.publisher.strip()
  233.     mi.cover_data = lrf.get_cover()
  234.     
  235.     try:
  236.         mi.title_sort = lrf.title_reading.strip()
  237.         if not mi.title_sort:
  238.             mi.title_sort = None
  239.     except:
  240.         pass
  241.  
  242.     
  243.     try:
  244.         mi.author_sort = lrf.author_reading.strip()
  245.         if not mi.author_sort:
  246.             mi.author_sort = None
  247.     except:
  248.         pass
  249.  
  250.     if not (mi.title) or 'unknown' in mi.title.lower():
  251.         mi.title = None
  252.     
  253.     if not mi.authors:
  254.         mi.authors = None
  255.     
  256.     if not (mi.author) or 'unknown' in mi.author.lower():
  257.         mi.author = None
  258.     
  259.     if not (mi.category) or 'unknown' in mi.category.lower():
  260.         mi.category = None
  261.     
  262.     if not (mi.publisher) and 'unknown' in mi.publisher.lower() or 'some publisher' in mi.publisher.lower():
  263.         mi.publisher = None
  264.     
  265.     return mi
  266.  
  267.  
  268. class LRFMetaFile(object):
  269.     LRF_HEADER = 'LRF'.encode('utf-16le')
  270.     lrf_header = fixed_stringfield(length = 6, start = 0)
  271.     version = field(fmt = WORD, start = 8)
  272.     xor_key = field(fmt = WORD, start = 10)
  273.     root_object_id = field(fmt = DWORD, start = 12)
  274.     number_of_objects = field(fmt = QWORD, start = 16)
  275.     object_index_offset = field(fmt = QWORD, start = 24)
  276.     binding = field(fmt = BYTE, start = 36)
  277.     dpi = field(fmt = WORD, start = 38)
  278.     width = field(fmt = WORD, start = 42)
  279.     height = field(fmt = WORD, start = 44)
  280.     color_depth = field(fmt = BYTE, start = 46)
  281.     toc_object_id = field(fmt = DWORD, start = 68)
  282.     toc_object_offset = field(fmt = DWORD, start = 72)
  283.     compressed_info_size = field(fmt = WORD, start = 76)
  284.     thumbnail_type = versioned_field(version, 800, fmt = WORD, start = 78)
  285.     thumbnail_size = versioned_field(version, 800, fmt = DWORD, start = 80)
  286.     uncompressed_info_size = versioned_field(compressed_info_size, 0, fmt = DWORD, start = 84)
  287.     title = xml_field('Title', parent = 'BookInfo')
  288.     title_reading = xml_attr_field('Title', 'reading', parent = 'BookInfo')
  289.     author = xml_field('Author', parent = 'BookInfo')
  290.     author_reading = xml_attr_field('Author', 'reading', parent = 'BookInfo')
  291.     book_id = xml_field('BookID', parent = 'BookInfo')
  292.     publisher = xml_field('Publisher', parent = 'BookInfo')
  293.     label = xml_field('Label', parent = 'BookInfo')
  294.     category = xml_field('Category', parent = 'BookInfo')
  295.     classification = xml_field('Classification', parent = 'BookInfo')
  296.     free_text = xml_field('FreeText', parent = 'BookInfo')
  297.     language = xml_field('Language', parent = 'DocInfo')
  298.     creator = xml_field('Creator', parent = 'DocInfo')
  299.     creation_date = xml_field('CreationDate', parent = 'DocInfo')
  300.     producer = xml_field('Producer', parent = 'DocInfo')
  301.     page = xml_field('SumPage', parent = 'DocInfo')
  302.     
  303.     def safe(func):
  304.         
  305.         def restore_pos(*args, **kwargs):
  306.             obj = args[0]
  307.             pos = obj._file.tell()
  308.             res = func(*args, **kwargs)
  309.             obj._file.seek(0, 2)
  310.             if obj._file.tell() >= pos:
  311.                 obj._file.seek(pos)
  312.             
  313.             return res
  314.  
  315.         restore_pos = (wraps(func),)(restore_pos)
  316.         return restore_pos
  317.  
  318.     
  319.     def safe_property(func):
  320.         
  321.         def decorator(f):
  322.             
  323.             def restore_pos(*args, **kwargs):
  324.                 obj = args[0]
  325.                 pos = obj._file.tell()
  326.                 res = f(*args, **kwargs)
  327.                 obj._file.seek(0, 2)
  328.                 if obj._file.tell() >= pos:
  329.                     obj._file.seek(pos)
  330.                 
  331.                 return res
  332.  
  333.             return restore_pos
  334.  
  335.         locals_ = func()
  336.         if locals_.has_key('fget'):
  337.             locals_['fget'] = decorator(locals_['fget'])
  338.         
  339.         if locals_.has_key('fset'):
  340.             locals_['fset'] = decorator(locals_['fset'])
  341.         
  342.         return property(**locals_)
  343.  
  344.     
  345.     def info():
  346.         doc = '\n        Document meta information as a minidom Document object.\n        To set use a minidom document object.\n        '
  347.         
  348.         def fget(self):
  349.             if self.compressed_info_size == 0:
  350.                 raise LRFException('This document has no meta info')
  351.             self.compressed_info_size == 0
  352.             size = self.compressed_info_size - 4
  353.             self._file.seek(self.info_start)
  354.             
  355.             try:
  356.                 src = zlib.decompress(self._file.read(size))
  357.                 if len(src) != self.uncompressed_info_size:
  358.                     raise LRFException('Decompression of document meta info                                        yielded unexpected results')
  359.                 len(src) != self.uncompressed_info_size
  360.                 
  361.                 try:
  362.                     return dom.parseString(src)
  363.                 except:
  364.                     
  365.                     try:
  366.                         return dom.parseString(src.replace('\x00', '').strip())
  367.                     src = src.replace('\x00', '').strip().decode('latin1')
  368.                     return dom.parseString(src.encode('utf-8'))
  369.  
  370.  
  371.             except zlib.error:
  372.                 raise LRFException('Unable to decompress document meta information')
  373.  
  374.  
  375.         
  376.         def fset(self, document):
  377.             info = document.toxml('utf-8')
  378.             self.uncompressed_info_size = len(info)
  379.             stream = zlib.compress(info)
  380.             orig_size = self.compressed_info_size
  381.             self.compressed_info_size = len(stream) + 4
  382.             delta = insert_into_file(self._file, stream, self.info_start, self.info_start + orig_size - 4)
  383.             if self.toc_object_offset > 0:
  384.                 self.toc_object_offset += delta
  385.             
  386.             self.object_index_offset += delta
  387.             self.update_object_offsets(delta)
  388.  
  389.         return {
  390.             'fget': fget,
  391.             'fset': fset,
  392.             'doc': doc }
  393.  
  394.     info = safe_property(info)
  395.     
  396.     def thumbnail_pos():
  397.         doc = ' The position of the thumbnail in the LRF file '
  398.         
  399.         def fget(self):
  400.             return self.info_start + self.compressed_info_size - 4
  401.  
  402.         return {
  403.             'fget': fget,
  404.             'doc': doc }
  405.  
  406.     thumbnail_pos = safe_property(thumbnail_pos)
  407.     
  408.     def _detect_thumbnail_type(cls, slice):
  409.         ttype = 20
  410.         if 'PNG' in slice:
  411.             ttype = 18
  412.         
  413.         if 'BM' in slice:
  414.             ttype = 19
  415.         
  416.         if 'JFIF' in slice:
  417.             ttype = 17
  418.         
  419.         return ttype
  420.  
  421.     _detect_thumbnail_type = classmethod(_detect_thumbnail_type)
  422.     
  423.     def thumbnail():
  424.         doc = '\n        The thumbnail.\n        Represented as a string.\n        The string you would get from the file read function.\n        '
  425.         
  426.         def fget(self):
  427.             size = self.thumbnail_size
  428.             if size:
  429.                 self._file.seek(self.thumbnail_pos)
  430.                 return self._file.read(size)
  431.  
  432.         
  433.         def fset(self, data):
  434.             if self.version <= 800:
  435.                 raise LRFException('Cannot store thumbnails in LRF files                                     of version <= 800')
  436.             self.version <= 800
  437.             slice = data[0:16]
  438.             orig_size = self.thumbnail_size
  439.             self.thumbnail_size = len(data)
  440.             delta = insert_into_file(self._file, data, self.thumbnail_pos, self.thumbnail_pos + orig_size)
  441.             self.toc_object_offset += delta
  442.             self.object_index_offset += delta
  443.             self.thumbnail_type = self._detect_thumbnail_type(slice)
  444.             self.update_object_offsets(delta)
  445.  
  446.         return {
  447.             'fget': fget,
  448.             'fset': fset,
  449.             'doc': doc }
  450.  
  451.     thumbnail = safe_property(thumbnail)
  452.     
  453.     def __init__(self, file):
  454.         file.seek(0, 2)
  455.         self.size = file.tell()
  456.         self._file = file
  457.         if self.lrf_header != LRFMetaFile.LRF_HEADER:
  458.             raise LRFException(file.name + ' has an invalid LRF header. Are you sure it is an LRF file?')
  459.         self.lrf_header != LRFMetaFile.LRF_HEADER
  460.         self.info_start = None if self.version > 800 else 83
  461.  
  462.     
  463.     def update_object_offsets(self, delta):
  464.         self._file.seek(self.object_index_offset)
  465.         count = self.number_of_objects
  466.         while count > 0:
  467.             raw = self._file.read(8)
  468.             new_offset = struct.unpack(DWORD, raw[4:8])[0] + delta
  469.             if new_offset >= 0x100000000L or new_offset < 76:
  470.                 raise LRFException(_('Invalid LRF file. Could not set metadata.'))
  471.             new_offset < 76
  472.             self._file.seek(-4, os.SEEK_CUR)
  473.             self._file.write(struct.pack(DWORD, new_offset))
  474.             self._file.seek(8, os.SEEK_CUR)
  475.             count -= 1
  476.         self._file.flush()
  477.  
  478.     update_object_offsets = safe(update_object_offsets)
  479.     
  480.     def unpack(self, fmt = DWORD, start = 0):
  481.         end = start + struct.calcsize(fmt)
  482.         self._file.seek(start)
  483.         ret = struct.unpack(fmt, self._file.read(end - start))
  484.         return ret
  485.  
  486.     unpack = safe(unpack)
  487.     
  488.     def pack(self, *args, **kwargs):
  489.         encoded = struct.pack(kwargs['fmt'], *args)
  490.         self._file.seek(kwargs['start'])
  491.         self._file.write(encoded)
  492.         self._file.flush()
  493.  
  494.     pack = safe(pack)
  495.     
  496.     def thumbail_extension(self):
  497.         ext = 'gif'
  498.         ttype = self.thumbnail_type
  499.         if ttype == 17:
  500.             ext = 'jpeg'
  501.         elif ttype == 18:
  502.             ext = 'png'
  503.         elif ttype == 19:
  504.             ext = 'bmp'
  505.         
  506.         return ext
  507.  
  508.     
  509.     def fix_thumbnail_type(self):
  510.         slice = self.thumbnail[0:16]
  511.         self.thumbnail_type = self._detect_thumbnail_type(slice)
  512.  
  513.     
  514.     def seek(self, *args):
  515.         return self._file.seek(*args)
  516.  
  517.     
  518.     def tell(self):
  519.         return self._file.tell()
  520.  
  521.     
  522.     def read(self):
  523.         return self._file.read()
  524.  
  525.     
  526.     def write(self, val):
  527.         self._file.write(val)
  528.  
  529.     
  530.     def _objects(self):
  531.         self._file.seek(self.object_index_offset)
  532.         c = self.number_of_objects
  533.         while c > 0:
  534.             c -= 1
  535.             raw = self._file.read(16)
  536.             pos = self._file.tell()
  537.             yield struct.unpack('<IIII', raw)[:3]
  538.             self._file.seek(pos)
  539.  
  540.     
  541.     def get_objects_by_type(self, type):
  542.         Tag = Tag
  543.         import calibre.ebooks.lrf.tags
  544.         objects = []
  545.         for id, offset, size in self._objects():
  546.             self._file.seek(offset)
  547.             tag = Tag(self._file)
  548.             if tag.id == 62720:
  549.                 (obj_id, obj_type) = struct.unpack('<IH', tag.contents)
  550.                 if obj_type == type:
  551.                     objects.append((obj_id, offset, size))
  552.                 
  553.             obj_type == type
  554.         
  555.         return objects
  556.  
  557.     
  558.     def get_object_by_id(self, tid):
  559.         Tag = Tag
  560.         import calibre.ebooks.lrf.tags
  561.         for id, offset, size in self._objects():
  562.             self._file.seek(offset)
  563.             tag = Tag(self._file)
  564.             if tag.id == 62720:
  565.                 (obj_id, obj_type) = struct.unpack('<IH', tag.contents)
  566.                 if obj_id == tid:
  567.                     return (obj_id, offset, size, obj_type)
  568.                 continue
  569.             obj_id == tid
  570.         
  571.         return (False, False, False, False)
  572.  
  573.     
  574.     def get_cover(self):
  575.         get_object = get_object
  576.         import calibre.ebooks.lrf.objects
  577.         for id, offset, size in self.get_objects_by_type(12):
  578.             image = get_object(None, self._file, id, offset, size, self.xor_key)
  579.             (id, offset, size) = self.get_object_by_id(image.refstream)[:3]
  580.             image_stream = get_object(None, self._file, id, offset, size, self.xor_key)
  581.             return (image_stream.file.rpartition('.')[-1], image_stream.stream)
  582.         
  583.  
  584.     get_cover = safe(get_cover)
  585.  
  586.  
  587. def option_parser():
  588.     OptionParser = OptionParser
  589.     import calibre.utils.config
  590.     __appname__ = __appname__
  591.     __version__ = __version__
  592.     import calibre.constants
  593.     parser = OptionParser(usage = _('%prog [options] mybook.lrf\n\n\nShow/edit the metadata in an LRF file.\n\n'), version = __appname__ + ' ' + __version__, epilog = 'Created by Kovid Goyal')
  594.     parser.add_option('-t', '--title', action = 'store', type = 'string', dest = 'title', help = _('Set the book title'))
  595.     parser.add_option('--title-sort', action = 'store', type = 'string', default = None, dest = 'title_reading', help = _('Set sort key for the title'))
  596.     parser.add_option('-a', '--author', action = 'store', type = 'string', dest = 'author', help = _('Set the author'))
  597.     parser.add_option('--author-sort', action = 'store', type = 'string', default = None, dest = 'author_reading', help = _('Set sort key for the author'))
  598.     parser.add_option('-c', '--category', action = 'store', type = 'string', dest = 'category', help = _('The category this book belongs to. E.g.: History'))
  599.     parser.add_option('--thumbnail', action = 'store', type = 'string', dest = 'thumbnail', help = _("Path to a graphic that will be set as this files' thumbnail"))
  600.     parser.add_option('--comment', action = 'store', type = 'string', dest = 'comment', help = _('Path to a txt file containing the comment to be stored in the lrf file.'))
  601.     parser.add_option('--get-thumbnail', action = 'store_true', dest = 'get_thumbnail', default = False, help = _('Extract thumbnail from LRF file'))
  602.     parser.add_option('--publisher', default = None, help = _('Set the publisher'))
  603.     parser.add_option('--classification', default = None, help = _('Set the book classification'))
  604.     parser.add_option('--creator', default = None, help = _('Set the book creator'))
  605.     parser.add_option('--producer', default = None, help = _('Set the book producer'))
  606.     parser.add_option('--get-cover', action = 'store_true', default = False, help = _('Extract cover from LRF file. Note that the LRF format has no defined cover, so we use some heuristics to guess the cover.'))
  607.     parser.add_option('--bookid', action = 'store', type = 'string', default = None, dest = 'book_id', help = _('Set book ID'))
  608.     return parser
  609.  
  610.  
  611. def set_metadata(stream, mi):
  612.     lrf = LRFMetaFile(stream)
  613.     if mi.title:
  614.         lrf.title = mi.title
  615.     
  616.     if mi.authors:
  617.         lrf.author = ', '.join(mi.authors)
  618.     
  619.     if mi.tags:
  620.         lrf.category = mi.tags[0]
  621.     
  622.     if getattr(mi, 'category', False):
  623.         lrf.category = mi.category
  624.     
  625.     if mi.comments:
  626.         lrf.free_text = mi.comments
  627.     
  628.     if mi.author_sort:
  629.         lrf.author_reading = mi.author_sort
  630.     
  631.     if mi.publisher:
  632.         lrf.publisher = mi.publisher
  633.     
  634.  
  635.  
  636. def main(args = sys.argv):
  637.     parser = option_parser()
  638.     (options, args) = parser.parse_args(args)
  639.     if len(args) != 2:
  640.         parser.print_help()
  641.         print 
  642.         print 'No lrf file specified'
  643.         return 1
  644.     lrf = LRFMetaFile(open(args[1], 'r+b'))
  645.     if options.title:
  646.         lrf.title = options.title
  647.     
  648.     if options.title_reading != None:
  649.         lrf.title_reading = options.title_reading
  650.     
  651.     if options.author_reading != None:
  652.         lrf.author_reading = options.author_reading
  653.     
  654.     if options.author:
  655.         lrf.author = options.author
  656.     
  657.     if options.publisher:
  658.         lrf.publisher = options.publisher
  659.     
  660.     if options.classification:
  661.         lrf.classification = options.classification
  662.     
  663.     if options.category:
  664.         lrf.category = options.category
  665.     
  666.     if options.creator:
  667.         lrf.creator = options.creator
  668.     
  669.     if options.producer:
  670.         lrf.producer = options.producer
  671.     
  672.     if options.thumbnail:
  673.         path = os.path.expanduser(os.path.expandvars(options.thumbnail))
  674.         f = open(path, 'rb')
  675.         lrf.thumbnail = f.read()
  676.         f.close()
  677.     
  678.     if options.book_id is not None:
  679.         lrf.book_id = options.book_id
  680.     
  681.     if options.comment:
  682.         path = os.path.expanduser(os.path.expandvars(options.comment))
  683.         lrf.free_text = open(path).read()
  684.     
  685.     if options.get_thumbnail:
  686.         t = lrf.thumbnail
  687.         td = 'None'
  688.         if t and len(t) > 0:
  689.             td = os.path.basename(args[1]) + '_thumbnail.' + lrf.thumbail_extension()
  690.             f = open(td, 'w')
  691.             f.write(t)
  692.             f.close()
  693.         
  694.     
  695.     fields = LRFMetaFile.__dict__.items()
  696.     fields.sort()
  697.     for f in fields:
  698.         if 'XML' in str(f):
  699.             print str(f[1]) + ':', lrf.__getattribute__(f[0]).encode('utf-8')
  700.             continue
  701.     
  702.     if options.get_thumbnail:
  703.         print 'Thumbnail:', td
  704.     
  705.     if options.get_cover:
  706.         
  707.         try:
  708.             (ext, data) = lrf.get_cover()
  709.         except:
  710.             (ext, data) = (None, None)
  711.  
  712.         if data:
  713.             cover = os.path.splitext(os.path.basename(args[1]))[0] + '_cover.' + ext
  714.             open(cover, 'wb').write(data)
  715.             print 'Cover:', cover
  716.         else:
  717.             print 'Could not find cover in the LRF file'
  718.     
  719.  
  720. if __name__ == '__main__':
  721.     sys.exit(main())
  722.  
  723.