home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_928 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  54.8 KB  |  1,804 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 array
  8. import zlib
  9. import cStringIO
  10. import collections
  11. import re
  12. from calibre.ebooks.lrf import LRFParseError, PRS500_PROFILE
  13. from calibre import entity_to_unicode, prepare_string_for_xml
  14. from calibre.ebooks.lrf.tags import Tag
  15. ruby_tags = {
  16.     62837: [
  17.         'rubyAlignAndAdjust',
  18.         'W'],
  19.     62838: [
  20.         'rubyoverhang',
  21.         'W',
  22.         {
  23.             0: 'none',
  24.             1: 'auto' }],
  25.     62839: [
  26.         'empdotsposition',
  27.         'W',
  28.         {
  29.             1: 'before',
  30.             2: 'after' }],
  31.     62840: [
  32.         '',
  33.         'parse_empdots'],
  34.     62841: [
  35.         'emplineposition',
  36.         'W',
  37.         {
  38.             1: 'before',
  39.             2: 'after' }],
  40.     62842: [
  41.         'emplinetype',
  42.         'W',
  43.         {
  44.             0: 'none',
  45.             16: 'solid',
  46.             32: 'dashed',
  47.             48: 'double',
  48.             64: 'dotted' }] }
  49.  
  50. class LRFObject(object):
  51.     tag_map = {
  52.         62720: [
  53.             '',
  54.             ''],
  55.         62722: [
  56.             'infoLink',
  57.             'D'],
  58.         62721: [
  59.             '',
  60.             ''] }
  61.     
  62.     def descramble_buffer(cls, buf, l, xorKey):
  63.         i = 0
  64.         a = array.array('B', buf)
  65.         while l > 0:
  66.             a[i] ^= xorKey
  67.             i += 1
  68.             l -= 1
  69.         return a.tostring()
  70.  
  71.     descramble_buffer = classmethod(descramble_buffer)
  72.     
  73.     def parse_empdots(self, tag, f):
  74.         (self.refEmpDotsFont, self.empDotsFontName, self.empDotsCode) = tag.contents
  75.  
  76.     parse_empdots = classmethod(parse_empdots)
  77.     
  78.     def tag_to_val(h, obj, tag, stream):
  79.         val = None
  80.         if h[1] == 'D':
  81.             val = tag.dword
  82.         elif h[1] == 'W':
  83.             val = tag.word
  84.         elif h[1] == 'w':
  85.             val = tag.word
  86.             if val > 32768:
  87.                 val -= 65536
  88.             
  89.         elif h[1] == 'B':
  90.             val = tag.byte
  91.         elif h[1] == 'P':
  92.             val = tag.contents
  93.         elif h[1] != '':
  94.             val = getattr(obj, h[1])(tag, stream)
  95.         
  96.         if len(h) > 2:
  97.             val = None if callable(h[2]) else h[2][val]
  98.         
  99.         return val
  100.  
  101.     tag_to_val = staticmethod(tag_to_val)
  102.     
  103.     def __init__(self, document, stream, id, scramble_key, boundary):
  104.         self._scramble_key = scramble_key
  105.         self._document = document
  106.         self.id = id
  107.         while stream.tell() < boundary:
  108.             tag = Tag(stream)
  109.             self.handle_tag(tag, stream)
  110.  
  111.     
  112.     def parse_bg_image(self, tag, f):
  113.         (self.bg_image_mode, self.bg_image_id) = struct.unpack('<HI', tag.contents)
  114.  
  115.     
  116.     def handle_tag(self, tag, stream, tag_map = None):
  117.         if tag_map is None:
  118.             tag_map = self.__class__.tag_map
  119.         
  120.         if tag.id in tag_map:
  121.             h = tag_map[tag.id]
  122.             val = LRFObject.tag_to_val(h, self, tag, stream)
  123.             if h[1] != '' and h[0] != '':
  124.                 setattr(self, h[0], val)
  125.             
  126.         else:
  127.             raise LRFParseError('Unknown tag in %s: %s' % (self.__class__.__name__, str(tag)))
  128.         return tag.id in tag_map
  129.  
  130.     
  131.     def __iter__(self):
  132.         for i in range(0):
  133.             yield i
  134.         
  135.  
  136.     
  137.     def __unicode__(self):
  138.         return unicode(self.__class__.__name__)
  139.  
  140.     
  141.     def __str__(self):
  142.         return unicode(self).encode('utf-8')
  143.  
  144.  
  145.  
  146. class LRFContentObject(LRFObject):
  147.     tag_map = { }
  148.     
  149.     def __init__(self, bytes, objects):
  150.         self.stream = None if hasattr(bytes, 'read') else cStringIO.StringIO(bytes)
  151.         length = self.stream_size()
  152.         self.objects = objects
  153.         self._contents = []
  154.         self.current = 0
  155.         self.in_container = True
  156.         self.parse_stream(length)
  157.  
  158.     
  159.     def parse_stream(self, length):
  160.         while self.in_container and self.stream.tell() < length:
  161.             tag = Tag(self.stream)
  162.             self.handle_tag(tag)
  163.  
  164.     
  165.     def stream_size(self):
  166.         pos = self.stream.tell()
  167.         self.stream.seek(0, 2)
  168.         size = self.stream.tell()
  169.         self.stream.seek(pos)
  170.         return size
  171.  
  172.     
  173.     def handle_tag(self, tag):
  174.         if tag.id in self.tag_map:
  175.             action = self.tag_map[tag.id]
  176.             if isinstance(action, basestring):
  177.                 func = action
  178.                 args = tuple([])
  179.             else:
  180.                 func = action[0]
  181.                 args = (action[1],)
  182.             getattr(self, func)(tag, *args)
  183.         else:
  184.             raise LRFParseError('Unknown tag in %s: %s' % (self.__class__.__name__, str(tag)))
  185.         return tag.id in self.tag_map
  186.  
  187.     
  188.     def __iter__(self):
  189.         for i in self._contents:
  190.             yield i
  191.         
  192.  
  193.  
  194.  
  195. class LRFStream(LRFObject):
  196.     tag_map = {
  197.         62724: [
  198.             '',
  199.             'read_stream_size'],
  200.         62804: [
  201.             'stream_flags',
  202.             'W'],
  203.         62725: [
  204.             '',
  205.             'read_stream'],
  206.         62726: [
  207.             '',
  208.             'end_stream'] }
  209.     tag_map.update(LRFObject.tag_map)
  210.     
  211.     def __init__(self, document, stream, id, scramble_key, boundary):
  212.         self.stream = ''
  213.         self.stream_size = 0
  214.         self.stream_read = False
  215.         LRFObject.__init__(self, document, stream, id, scramble_key, boundary)
  216.  
  217.     
  218.     def read_stream_size(self, tag, stream):
  219.         self.stream_size = tag.dword
  220.  
  221.     
  222.     def end_stream(self, tag, stream):
  223.         self.stream_read = True
  224.  
  225.     
  226.     def read_stream(self, tag, stream):
  227.         if self.stream_read:
  228.             raise LRFParseError('There can be only one stream per object')
  229.         self.stream_read
  230.         if not hasattr(self, 'stream_flags'):
  231.             raise LRFParseError('Stream flags not initialized')
  232.         hasattr(self, 'stream_flags')
  233.         self.stream = stream.read(self.stream_size)
  234.         if self.stream_flags & 512 != 0:
  235.             l = len(self.stream)
  236.             key = self._scramble_key & 255
  237.             if key != 0 and key <= 240:
  238.                 key = l % key + 15
  239.             else:
  240.                 key = 0
  241.             if l > 1024:
  242.                 if isinstance(self, ImageStream) and isinstance(self, Font) or isinstance(self, SoundStream):
  243.                     l = 1024
  244.                 
  245.             self.stream = self.descramble_buffer(self.stream, l, key)
  246.         
  247.         if self.stream_flags & 256 != 0:
  248.             decomp_size = struct.unpack('<I', self.stream[:4])[0]
  249.             self.stream = zlib.decompress(self.stream[4:])
  250.             if len(self.stream) != decomp_size:
  251.                 raise LRFParseError('Stream decompressed size is wrong!')
  252.             len(self.stream) != decomp_size
  253.         
  254.         if stream.read(2) != '\x06\xf5':
  255.             print 'Warning: corrupted end-of-stream tag at %08X; skipping it' % (stream.tell() - 2)
  256.         
  257.         self.end_stream(None, None)
  258.  
  259.  
  260.  
  261. class PageTree(LRFObject):
  262.     tag_map = {
  263.         62812: [
  264.             '_contents',
  265.             'P'] }
  266.     tag_map.update(LRFObject.tag_map)
  267.     
  268.     def __iter__(self):
  269.         for id in getattr(self, '_contents', []):
  270.             yield self._document.objects[id]
  271.         
  272.  
  273.  
  274.  
  275. class StyleObject(object):
  276.     
  277.     def _tags_to_xml(self):
  278.         s = u''
  279.         for h in self.tag_map.values():
  280.             attr = h[0]
  281.             if hasattr(self, attr):
  282.                 s += u'%s="%s" ' % (attr, getattr(self, attr))
  283.                 continue
  284.         
  285.         return s
  286.  
  287.     
  288.     def __unicode__(self):
  289.         s = u'<%s objid="%s" stylelabel="%s" ' % (self.__class__.__name__.replace('Attr', 'Style'), self.id, self.id)
  290.         s += self._tags_to_xml()
  291.         s += u'/>\n'
  292.         return s
  293.  
  294.     
  295.     def as_dict(self):
  296.         d = { }
  297.         for h in self.tag_map.values():
  298.             attr = h[0]
  299.             if hasattr(self, attr):
  300.                 d[attr] = getattr(self, attr)
  301.                 continue
  302.         
  303.         return d
  304.  
  305.  
  306.  
  307. class PageAttr(StyleObject, LRFObject):
  308.     tag_map = {
  309.         62727: [
  310.             'oddheaderid',
  311.             'D'],
  312.         62728: [
  313.             'evenheaderid',
  314.             'D'],
  315.         62729: [
  316.             'oddfooterid',
  317.             'D'],
  318.         62730: [
  319.             'evenfooterid',
  320.             'D'],
  321.         62753: [
  322.             'topmargin',
  323.             'W'],
  324.         62754: [
  325.             'headheight',
  326.             'W'],
  327.         62755: [
  328.             'headsep',
  329.             'W'],
  330.         62756: [
  331.             'oddsidemargin',
  332.             'W'],
  333.         62764: [
  334.             'evensidemargin',
  335.             'W'],
  336.         62757: [
  337.             'textheight',
  338.             'W'],
  339.         62758: [
  340.             'textwidth',
  341.             'W'],
  342.         62759: [
  343.             'footspace',
  344.             'W'],
  345.         62760: [
  346.             'footheight',
  347.             'W'],
  348.         62773: [
  349.             'layout',
  350.             'W',
  351.             {
  352.                 65: 'TbRl',
  353.                 52: 'LrTb' }],
  354.         62763: [
  355.             'pageposition',
  356.             'W',
  357.             {
  358.                 0: 'any',
  359.                 1: 'upper',
  360.                 2: 'lower' }],
  361.         62762: [
  362.             'setemptyview',
  363.             'W',
  364.             {
  365.                 1: 'show',
  366.                 0: 'empty' }],
  367.         62938: [
  368.             'setwaitprop',
  369.             'W',
  370.             {
  371.                 1: 'replay',
  372.                 2: 'noreplay' }],
  373.         62761: [
  374.             '',
  375.             'parse_bg_image'] }
  376.     tag_map.update(LRFObject.tag_map)
  377.     
  378.     def to_css(cls, obj, inline = False):
  379.         return ''
  380.  
  381.     to_css = classmethod(to_css)
  382.  
  383.  
  384. class Color(object):
  385.     
  386.     def __init__(self, val):
  387.         (self.a, self.r, self.g, self.b) = (val & 255, val >> 8 & 255, val >> 16 & 255, val >> 24 & 255)
  388.  
  389.     
  390.     def __unicode__(self):
  391.         return u'0x%02x%02x%02x%02x' % (self.a, self.r, self.g, self.b)
  392.  
  393.     
  394.     def __str__(self):
  395.         return unicode(self)
  396.  
  397.     
  398.     def __len__(self):
  399.         return 4
  400.  
  401.     
  402.     def __getitem__(self, i):
  403.         return (self.r, self.g, self.b, 255 - self.a)[i]
  404.  
  405.     
  406.     def to_html(self):
  407.         return 'rgb(%d, %d, %d)' % (self.r, self.g, self.b)
  408.  
  409.  
  410.  
  411. class EmptyPageElement(object):
  412.     
  413.     def __iter__(self):
  414.         for i in range(0):
  415.             yield i
  416.         
  417.  
  418.     
  419.     def __str__(self):
  420.         return unicode(self)
  421.  
  422.  
  423.  
  424. class PageDiv(EmptyPageElement):
  425.     
  426.     def __init__(self, pain, spacesize, linewidth, linecolor):
  427.         self.pain = pain
  428.         self.spacesize = spacesize
  429.         self.linewidth = linewidth
  430.         self.linecolor = Color(linecolor)
  431.  
  432.     
  433.     def __unicode__(self):
  434.         return u'\n<PageDiv pain="%s" spacesize="%s" linewidth="%s" linecolor="%s" />\n' % (self.pain, self.spacesize, self.linewidth, self.color)
  435.  
  436.  
  437.  
  438. class RuledLine(EmptyPageElement):
  439.     linetype_map = {
  440.         0: 'none',
  441.         16: 'solid',
  442.         32: 'dashed',
  443.         48: 'double',
  444.         64: 'dotted',
  445.         19: 'unknown13' }
  446.     
  447.     def __init__(self, linelength, linetype, linewidth, linecolor):
  448.         self.linelength = linelength
  449.         self.linewidth = linewidth
  450.         self.linetype = self.linetype_map[linetype]
  451.         self.linecolor = Color(linecolor)
  452.         self.id = -1
  453.  
  454.     
  455.     def __unicode__(self):
  456.         return u'\n<RuledLine linelength="%s" linetype="%s" linewidth="%s" linecolor="%s" />\n' % (self.linelength, self.linetype, self.linewidth, self.linecolor)
  457.  
  458.  
  459.  
  460. class Wait(EmptyPageElement):
  461.     
  462.     def __init__(self, time):
  463.         self.time = time
  464.  
  465.     
  466.     def __unicode__(self):
  467.         return u'\n<Wait time="%d" />\n' % self.time
  468.  
  469.  
  470.  
  471. class Locate(EmptyPageElement):
  472.     pos_map = {
  473.         1: 'bottomleft',
  474.         2: 'bottomright',
  475.         3: 'topright',
  476.         4: 'topleft',
  477.         5: 'base' }
  478.     
  479.     def __init__(self, pos):
  480.         self.pos = self.pos_map[pos]
  481.  
  482.     
  483.     def __unicode__(self):
  484.         return u'\n<Locate pos="%s" />\n' % self.pos
  485.  
  486.  
  487.  
  488. class BlockSpace(EmptyPageElement):
  489.     
  490.     def __init__(self, xspace, yspace):
  491.         self.xspace = xspace
  492.         self.yspace = yspace
  493.  
  494.     
  495.     def __unicode__(self):
  496.         return u'\n<BlockSpace xspace="%d" yspace="%d" />\n' % (self.xspace, self.yspace)
  497.  
  498.  
  499.  
  500. class Page(LRFStream):
  501.     tag_map = {
  502.         62723: [
  503.             'style_id',
  504.             'D'],
  505.         62731: [
  506.             'obj_list',
  507.             'P'],
  508.         62833: [
  509.             '',
  510.             ''],
  511.         62844: [
  512.             'parent_page_tree',
  513.             'D'] }
  514.     tag_map.update(PageAttr.tag_map)
  515.     tag_map.update(LRFStream.tag_map)
  516.     style = property(fget = (lambda self: self._document.objects[self.style_id]))
  517.     evenheader = property(fget = (lambda self: self._document.objects[self.style.evenheaderid]))
  518.     evenfooter = property(fget = (lambda self: self._document.objects[self.style.evenfooterid]))
  519.     oddheader = property(fget = (lambda self: self._document.objects[self.style.oddheaderid]))
  520.     oddfooter = property(fget = (lambda self: self._document.objects[self.style.oddfooterid]))
  521.     
  522.     class Content(LRFContentObject):
  523.         tag_map = {
  524.             62723: 'link',
  525.             62798: 'page_div',
  526.             62791: 'x_space',
  527.             62790: 'y_space',
  528.             62792: 'do_pos',
  529.             62835: 'ruled_line',
  530.             62932: 'wait',
  531.             62934: 'sound_stop' }
  532.         
  533.         def __init__(self, bytes, objects):
  534.             self.in_blockspace = False
  535.             LRFContentObject.__init__(self, bytes, objects)
  536.  
  537.         
  538.         def link(self, tag):
  539.             self.close_blockspace()
  540.             self._contents.append(self.objects[tag.dword])
  541.  
  542.         
  543.         def page_div(self, tag):
  544.             self.close_blockspace()
  545.             pars = struct.unpack('<HIHI', tag.contents)
  546.             self._contents.append(PageDiv(*pars))
  547.  
  548.         
  549.         def x_space(self, tag):
  550.             self.xspace = tag.word
  551.             self.in_blockspace = True
  552.  
  553.         
  554.         def y_space(self, tag):
  555.             self.yspace = tag.word
  556.             self.in_blockspace = True
  557.  
  558.         
  559.         def do_pos(self, tag):
  560.             self.pos = tag.wordself.pos_map[tag.word]
  561.             self.in_blockspace = True
  562.  
  563.         
  564.         def ruled_line(self, tag):
  565.             self.close_blockspace()
  566.             pars = struct.unpack('<HHHI', tag.contents)
  567.             self._contents.append(RuledLine(*pars))
  568.  
  569.         
  570.         def wait(self, tag):
  571.             self.close_blockspace()
  572.             self._contents.append(Wait(tag.word))
  573.  
  574.         
  575.         def sound_stop(self, tag):
  576.             self.close_blockspace()
  577.  
  578.         
  579.         def close_blockspace(self):
  580.             if self.in_blockspace:
  581.                 if hasattr(self, 'pos'):
  582.                     self._contents.append(Locate(self.pos))
  583.                     delattr(self, 'pos')
  584.                 elif hasattr(self, 'xspace'):
  585.                     pass
  586.                 
  587.                 xspace = 0
  588.                 yspace = None if hasattr(self, 'yspace') else 0
  589.                 self._contents.append(BlockSpace(xspace, yspace))
  590.                 if hasattr(self, 'xspace'):
  591.                     delattr(self, 'xspace')
  592.                 
  593.                 if hasattr(self, 'yspace'):
  594.                     delattr(self, 'yspace')
  595.                 
  596.             
  597.  
  598.  
  599.     
  600.     def header(self, odd):
  601.         id = None if odd else self._document.objects[self.style_id].evenheaderid
  602.         return self._document.objects[id]
  603.  
  604.     
  605.     def footer(self, odd):
  606.         id = None if odd else self._document.objects[self.style_id].evenfooterid
  607.         return self._document.objects[id]
  608.  
  609.     
  610.     def initialize(self):
  611.         self.content = Page.Content(self.stream, self._document.objects)
  612.  
  613.     
  614.     def __iter__(self):
  615.         for i in self.content:
  616.             yield i
  617.         
  618.  
  619.     
  620.     def __unicode__(self):
  621.         s = u'\n<Page pagestyle="%d" objid="%d">\n' % (self.style_id, self.id)
  622.         for i in self:
  623.             s += unicode(i)
  624.         
  625.         s += '\n</Page>\n'
  626.         return s
  627.  
  628.     
  629.     def __str__(self):
  630.         return unicode(self)
  631.  
  632.     
  633.     def to_html(self):
  634.         s = u''
  635.         for i in self:
  636.             s += i.to_html()
  637.         
  638.         return s
  639.  
  640.  
  641.  
  642. class BlockAttr(StyleObject, LRFObject):
  643.     tag_map = {
  644.         62769: [
  645.             'blockwidth',
  646.             'W'],
  647.         62770: [
  648.             'blockheight',
  649.             'W'],
  650.         62771: [
  651.             'blockrule',
  652.             'W',
  653.             {
  654.                 20: 'horz-fixed',
  655.                 18: 'horz-adjustable',
  656.                 65: 'vert-fixed',
  657.                 33: 'vert-adjustable',
  658.                 68: 'block-fixed',
  659.                 34: 'block-adjustable' }],
  660.         62772: [
  661.             'bgcolor',
  662.             'D',
  663.             Color],
  664.         62773: [
  665.             'layout',
  666.             'W',
  667.             {
  668.                 65: 'TbRl',
  669.                 52: 'LrTb' }],
  670.         62774: [
  671.             'framewidth',
  672.             'W'],
  673.         62775: [
  674.             'framecolor',
  675.             'D',
  676.             Color],
  677.         62766: [
  678.             'framemode',
  679.             'W',
  680.             {
  681.                 0: 'none',
  682.                 2: 'curve',
  683.                 1: 'square' }],
  684.         62776: [
  685.             'topskip',
  686.             'W'],
  687.         62777: [
  688.             'sidemargin',
  689.             'W'],
  690.         62778: [
  691.             'footskip',
  692.             'W'],
  693.         62761: [
  694.             '',
  695.             'parse_bg_image'] }
  696.     tag_map.update(LRFObject.tag_map)
  697.     
  698.     def to_css(cls, obj, inline = False):
  699.         ans = ''
  700.         
  701.         def item(line):
  702.             None += ans if inline else '\t'
  703.             ans += line
  704.             None += ans if inline else '\n'
  705.  
  706.         if hasattr(obj, 'sidemargin'):
  707.             margin = str(obj.sidemargin) + 'px'
  708.             item('margin-left: %(m)s; margin-right: %(m)s;' % dict(m = margin))
  709.         
  710.         if hasattr(obj, 'topskip'):
  711.             item('margin-top: %dpx;' % obj.topskip)
  712.         
  713.         if hasattr(obj, 'footskip'):
  714.             item('margin-bottom: %dpx;' % obj.footskip)
  715.         
  716.         if hasattr(obj, 'framewidth'):
  717.             item('border: solid %dpx' % obj.framewidth)
  718.         
  719.         if hasattr(obj, 'framecolor') and obj.framecolor.a < 255:
  720.             item('border-color: %s;' % obj.framecolor.to_html())
  721.         
  722.         if hasattr(obj, 'bgcolor') and obj.bgcolor.a < 255:
  723.             item('background-color: %s;' % obj.bgcolor.to_html())
  724.         
  725.         return ans
  726.  
  727.     to_css = classmethod(to_css)
  728.  
  729.  
  730. class TextCSS(object):
  731.     
  732.     def to_css(cls, obj, inline = False):
  733.         ans = ''
  734.         
  735.         def item(line):
  736.             None += ans if inline else '\t'
  737.             ans += line
  738.             None += ans if inline else '\n'
  739.  
  740.         fs = getattr(obj, 'fontsize', None)
  741.         if fs is not None:
  742.             item('font-size: %fpt;' % int(fs) / 10)
  743.         
  744.         fw = getattr(obj, 'fontweight', None)
  745.         if fw is not None:
  746.             None(item % 'font-weight: %s;' if int(fw) >= 700 else 'normal')
  747.         
  748.         fn = getattr(obj, 'fontfacename', None)
  749.         if fn is not None:
  750.             fn = cls.FONT_MAP[fn]
  751.             item('font-family: %s;' % fn)
  752.         
  753.         fg = getattr(obj, 'textcolor', None)
  754.         if fg is not None:
  755.             fg = fg.to_html()
  756.             item('color: %s;' % fg)
  757.         
  758.         bg = getattr(obj, 'textbgcolor', None)
  759.         if bg is not None:
  760.             bg = bg.to_html()
  761.             item('background-color: %s;' % bg)
  762.         
  763.         al = getattr(obj, 'align', None)
  764.         if al is not None:
  765.             al = dict(head = 'left', center = 'center', foot = 'right')
  766.             item('text-align: %s;' % al)
  767.         
  768.         lh = getattr(obj, 'linespace', None)
  769.         if lh is not None:
  770.             item('text-align: %fpt;' % int(lh) / 10)
  771.         
  772.         pi = getattr(obj, 'parindent', None)
  773.         if pi is not None:
  774.             item('text-indent: %fpt;' % int(pi) / 10)
  775.         
  776.         return ans
  777.  
  778.     to_css = classmethod(to_css)
  779.  
  780.  
  781. class TextAttr(StyleObject, LRFObject, TextCSS):
  782.     FONT_MAP = collections.defaultdict((lambda : 'serif'))
  783.     for key, value in PRS500_PROFILE.default_fonts.items():
  784.         FONT_MAP[value] = key
  785.     
  786.     tag_map = {
  787.         62737: [
  788.             'fontsize',
  789.             'w'],
  790.         62738: [
  791.             'fontwidth',
  792.             'w'],
  793.         62739: [
  794.             'fontescapement',
  795.             'w'],
  796.         62740: [
  797.             'fontorientation',
  798.             'w'],
  799.         62741: [
  800.             'fontweight',
  801.             'W'],
  802.         62742: [
  803.             'fontfacename',
  804.             'P'],
  805.         62743: [
  806.             'textcolor',
  807.             'D',
  808.             Color],
  809.         62744: [
  810.             'textbgcolor',
  811.             'D',
  812.             Color],
  813.         62745: [
  814.             'wordspace',
  815.             'w'],
  816.         62746: [
  817.             'letterspace',
  818.             'w'],
  819.         62747: [
  820.             'baselineskip',
  821.             'w'],
  822.         62748: [
  823.             'linespace',
  824.             'w'],
  825.         62749: [
  826.             'parindent',
  827.             'w'],
  828.         62750: [
  829.             'parskip',
  830.             'w'],
  831.         62780: [
  832.             'align',
  833.             'W',
  834.             {
  835.                 1: 'head',
  836.                 4: 'center',
  837.                 8: 'foot' }],
  838.         62781: [
  839.             'column',
  840.             'W'],
  841.         62782: [
  842.             'columnsep',
  843.             'W'],
  844.         62941: [
  845.             'charspace',
  846.             'w'],
  847.         62961: [
  848.             'textlinewidth',
  849.             'W'],
  850.         62962: [
  851.             'linecolor',
  852.             'D',
  853.             Color] }
  854.     tag_map.update(ruby_tags)
  855.     tag_map.update(LRFObject.tag_map)
  856.  
  857.  
  858. class Block(LRFStream, TextCSS):
  859.     tag_map = {
  860.         62723: [
  861.             'style_id',
  862.             'D'] }
  863.     tag_map.update(BlockAttr.tag_map)
  864.     tag_map.update(TextAttr.tag_map)
  865.     tag_map.update(LRFStream.tag_map)
  866.     extra_attrs = [ i[0] for i in BlockAttr.tag_map.values() ]
  867.     []([ i[0] for i in TextAttr.tag_map.values() ])
  868.     style = property(fget = (lambda self: self._document.objects[self.style_id]))
  869.     textstyle = property(fget = (lambda self: self._document.objects[self.textstyle_id]))
  870.     
  871.     def initialize(self):
  872.         self.attrs = { }
  873.         stream = cStringIO.StringIO(self.stream)
  874.         tag = Tag(stream)
  875.         if tag.id != 62723:
  876.             raise LRFParseError('Bad block content')
  877.         tag.id != 62723
  878.         obj = self._document.objects[tag.dword]
  879.         if isinstance(obj, SimpleText):
  880.             self.name = 'SimpleTextBlock'
  881.             self.textstyle_id = obj.style_id
  882.         elif isinstance(obj, Text):
  883.             self.name = 'TextBlock'
  884.             self.textstyle_id = obj.style_id
  885.         elif isinstance(obj, Image):
  886.             self.name = 'ImageBlock'
  887.             for attr in ('x0', 'x1', 'y0', 'y1', 'xsize', 'ysize', 'refstream'):
  888.                 self.attrs[attr] = getattr(obj, attr)
  889.             
  890.             self.refstream = self._document.objects[self.attrs['refstream']]
  891.         elif isinstance(obj, Button):
  892.             self.name = 'ButtonBlock'
  893.         else:
  894.             raise LRFParseError('Unexpected block type: ' + obj.__class__.__name__)
  895.         self.content = isinstance(obj, SimpleText)
  896.         for attr in self.extra_attrs:
  897.             if hasattr(self, attr):
  898.                 self.attrs[attr] = getattr(self, attr)
  899.                 continue
  900.         
  901.  
  902.     
  903.     def __unicode__(self):
  904.         s = u'\n<%s objid="%d" blockstyle="%d" ' % (self.name, self.id, self.style_id)
  905.         if hasattr(self, 'textstyle_id'):
  906.             s += 'textstyle="%d" ' % (self.textstyle_id,)
  907.         
  908.         for attr in self.attrs:
  909.             s += '%s="%s" ' % (attr, self.attrs[attr])
  910.         
  911.         if self.name != 'ImageBlock':
  912.             s = s.rstrip() + '>\n'
  913.             s += unicode(self.content)
  914.             s += '</%s>\n' % (self.name,)
  915.             return s
  916.         return s.rstrip() + ' />\n'
  917.  
  918.     
  919.     def to_html(self):
  920.         if self.name == 'TextBlock':
  921.             return u'<div class="block%s text%s">%s</div>' % (self.style_id, self.textstyle_id, self.content.to_html())
  922.         return u''
  923.  
  924.  
  925.  
  926. class MiniPage(LRFStream):
  927.     tag_map = {
  928.         62785: [
  929.             'minipagewidth',
  930.             'W'],
  931.         62786: [
  932.             'minipageheight',
  933.             'W'] }
  934.     tag_map.update(LRFStream.tag_map)
  935.     tag_map.update(BlockAttr.tag_map)
  936.  
  937.  
  938. class Text(LRFStream):
  939.     tag_map = {
  940.         62723: [
  941.             'style_id',
  942.             'D'] }
  943.     tag_map.update(TextAttr.tag_map)
  944.     tag_map.update(LRFStream.tag_map)
  945.     style = property(fget = (lambda self: self._document.objects[self.style_id]))
  946.     text_map = {
  947.         34: u'"',
  948.         38: u'&',
  949.         39: u"'",
  950.         60: u'<',
  951.         62: u'>' }
  952.     entity_pattern = re.compile('&(\\S+?);')
  953.     text_tags = {
  954.         62849: [
  955.             'simple_container',
  956.             'Italic'],
  957.         62850: 'end_container',
  958.         62897: [
  959.             'simple_container',
  960.             'Yoko'],
  961.         62898: 'end_container',
  962.         62899: [
  963.             'simple_container',
  964.             'Tate'],
  965.         62900: 'end_container',
  966.         62901: [
  967.             'simple_container',
  968.             'Nekase'],
  969.         62902: 'end_container',
  970.         62881: 'start_para',
  971.         62882: 'end_para',
  972.         62887: 'char_button',
  973.         62888: 'end_container',
  974.         62889: [
  975.             'simple_container',
  976.             'Rubi'],
  977.         62890: 'end_container',
  978.         62891: [
  979.             'simple_container',
  980.             'Oyamoji'],
  981.         62892: 'end_container',
  982.         62893: [
  983.             'simple_container',
  984.             'Rubimoji'],
  985.         62894: 'end_container',
  986.         62903: [
  987.             'simple_container',
  988.             'Sup'],
  989.         62904: 'end_container',
  990.         62905: [
  991.             'simple_container',
  992.             'Sub'],
  993.         62906: 'end_container',
  994.         62907: [
  995.             'simple_container',
  996.             'NoBR'],
  997.         62908: 'end_container',
  998.         62909: [
  999.             'simple_container',
  1000.             'EmpDots'],
  1001.         62910: 'end_container',
  1002.         62913: 'empline',
  1003.         62914: 'end_container',
  1004.         62915: 'draw_char',
  1005.         62916: 'end_container',
  1006.         62918: 'box',
  1007.         62919: 'end_container',
  1008.         62922: 'space',
  1009.         62929: 'plot',
  1010.         62930: 'cr' }
  1011.     
  1012.     class TextTag(object):
  1013.         
  1014.         def __init__(self, name, attrs = { }, self_closing = False):
  1015.             self.name = name
  1016.             self.attrs = attrs
  1017.             self.self_closing = self_closing
  1018.  
  1019.         
  1020.         def __unicode__(self):
  1021.             s = u'<%s ' % (self.name,)
  1022.             for name, val in self.attrs.items():
  1023.                 s += '%s="%s" ' % (name, val)
  1024.             
  1025.             return None + s.rstrip() if self.self_closing else u'>'
  1026.  
  1027.         
  1028.         def to_html(self):
  1029.             s = u''
  1030.             return s
  1031.  
  1032.         
  1033.         def close_html(self):
  1034.             return u''
  1035.  
  1036.  
  1037.     
  1038.     class Span(TextTag):
  1039.         pass
  1040.  
  1041.     linetype_map = {
  1042.         0: 'none',
  1043.         16: 'solid',
  1044.         32: 'dashed',
  1045.         48: 'double',
  1046.         64: 'dotted' }
  1047.     adjustment_map = {
  1048.         1: 'top',
  1049.         2: 'center',
  1050.         3: 'baseline',
  1051.         4: 'bottom' }
  1052.     lineposition_map = {
  1053.         1: 'before',
  1054.         2: 'after' }
  1055.     
  1056.     def add_text(self, text):
  1057.         s = unicode(text, 'utf-16-le')
  1058.         if s:
  1059.             s = s.translate(self.text_map)
  1060.             self.content.append(self.entity_pattern.sub(entity_to_unicode, s))
  1061.         
  1062.  
  1063.     
  1064.     def end_container(self, tag, stream):
  1065.         self.content.append(None)
  1066.  
  1067.     
  1068.     def start_para(self, tag, stream):
  1069.         self.content.append(self.__class__.TextTag('P'))
  1070.  
  1071.     
  1072.     def close_containers(self, start = 0):
  1073.         if len(self.content) == 0:
  1074.             return None
  1075.         open_containers = 0
  1076.         if len(self.content) > 0 and isinstance(self.content[-1], self.__class__.Span):
  1077.             self.content.pop()
  1078.         
  1079.         while start < len(self.content):
  1080.             c = self.content[start]
  1081.             if c is None:
  1082.                 open_containers -= 1
  1083.             elif isinstance(c, self.__class__.TextTag) and not (c.self_closing):
  1084.                 open_containers += 1
  1085.             
  1086.             start += 1
  1087.         self.content.extend((lambda .0: for i in .0:
  1088. None)(range(open_containers)))
  1089.  
  1090.     
  1091.     def end_para(self, tag, stream):
  1092.         i = len(self.content) - 1
  1093.         while i > -1:
  1094.             if isinstance(self.content[i], Text.TextTag) and self.content[i].name == 'P':
  1095.                 break
  1096.             
  1097.             i -= 1
  1098.         self.close_containers(start = i)
  1099.  
  1100.     
  1101.     def cr(self, tag, stream):
  1102.         self.content.append(self.__class__.TextTag('CR', self_closing = True))
  1103.  
  1104.     
  1105.     def char_button(self, tag, stream):
  1106.         self.content.append(self.__class__.TextTag('CharButton', attrs = {
  1107.             'refobj': tag.dword }))
  1108.  
  1109.     
  1110.     def simple_container(self, tag, name):
  1111.         self.content.append(self.__class__.TextTag(name))
  1112.  
  1113.     
  1114.     def empline(self, tag, stream):
  1115.         
  1116.         def invalid(op):
  1117.             stream.seek(op)
  1118.  
  1119.         oldpos = stream.tell()
  1120.         
  1121.         try:
  1122.             t = Tag(stream)
  1123.             if t.id not in (62841, 62842):
  1124.                 raise LRFParseError
  1125.             t.id not in (62841, 62842)
  1126.         except LRFParseError:
  1127.             (None,)
  1128.             (None,)
  1129.             invalid(oldpos)
  1130.             return None
  1131.  
  1132.         h = TextAttr.tag_map[t.id]
  1133.         attrs = { }
  1134.         attrs[h[0]] = TextAttr.tag_to_val(h, None, t, None)
  1135.         oldpos = stream.tell()
  1136.         
  1137.         try:
  1138.             t = Tag(stream)
  1139.             if t.id not in (62841, 62842):
  1140.                 raise LRFParseError
  1141.             t.id not in (62841, 62842)
  1142.             h = TextAttr.tag_map[t.id]
  1143.             attrs[h[0]] = TextAttr.tag_to_val(h, None, t, None)
  1144.         except LRFParseError:
  1145.             (None,)
  1146.             (None,)
  1147.             stream.seek(oldpos)
  1148.         except:
  1149.             (None,)
  1150.  
  1151.         if attrs:
  1152.             self.content.append(self.__class__.TextTag('EmpLine', attrs = attrs))
  1153.         
  1154.  
  1155.     
  1156.     def space(self, tag, stream):
  1157.         self.content.append(self.__class__.TextTag('Space', attrs = {
  1158.             'xsize': tag.sword }, self_closing = True))
  1159.  
  1160.     
  1161.     def plot(self, tag, stream):
  1162.         (xsize, ysize, refobj, adjustment) = struct.unpack('<HHII', tag.contents)
  1163.         plot = self.__class__.TextTag('Plot', {
  1164.             'xsize': xsize,
  1165.             'ysize': ysize,
  1166.             'refobj': refobj,
  1167.             'adjustment': self.adjustment_map[adjustment] }, self_closing = True)
  1168.         plot.refobj = self._document.objects[refobj]
  1169.         self.content.append(plot)
  1170.  
  1171.     
  1172.     def draw_char(self, tag, stream):
  1173.         self.content.append(self.__class__.TextTag('DrawChar', {
  1174.             'line': tag.word }))
  1175.  
  1176.     
  1177.     def box(self, tag, stream):
  1178.         self.content.append(self.__class__.TextTag('Box', {
  1179.             'linetype': self.linetype_map[tag.word] }))
  1180.  
  1181.     
  1182.     def initialize(self):
  1183.         self.content = collections.deque()
  1184.         stream = cStringIO.StringIO(self.stream)
  1185.         length = len(self.stream)
  1186.         style = self.style.as_dict()
  1187.         current_style = style.copy()
  1188.         text_tags = set(list(TextAttr.tag_map.keys()) + list(Text.text_tags.keys()) + list(ruby_tags.keys()))
  1189.         [] -= []([ 62720 + i for i in range(10) ])
  1190.         text_tags.add(62924)
  1191.         while stream.tell() < length:
  1192.             
  1193.             def find_first_tag(start):
  1194.                 pos = self.stream.find('\xf5', start)
  1195.                 if pos == -1:
  1196.                     return -1
  1197.                 
  1198.                 try:
  1199.                     stream.seek(pos - 1)
  1200.                     _t = Tag(stream)
  1201.                     if _t.id in text_tags:
  1202.                         return pos - 1
  1203.                     return find_first_tag(pos + 1)
  1204.                 except:
  1205.                     pos == -1
  1206.                     return find_first_tag(pos + 1)
  1207.  
  1208.  
  1209.             start_pos = stream.tell()
  1210.             tag_pos = find_first_tag(start_pos)
  1211.             tag = Tag(stream)
  1212.             if tag.id == 62924:
  1213.                 self.add_text(stream.read(tag.word))
  1214.                 continue
  1215.             None if tag_pos >= start_pos else (None, None, text_tags, set)
  1216.             if tag.id in self.__class__.text_tags:
  1217.                 action = self.__class__.text_tags[tag.id]
  1218.                 if isinstance(action, basestring):
  1219.                     getattr(self, action)(tag, stream)
  1220.                 else:
  1221.                     getattr(self, action[0])(tag, action[1])
  1222.             isinstance(action, basestring)
  1223.             if tag.id in TextAttr.tag_map:
  1224.                 action = TextAttr.tag_map[tag.id]
  1225.                 if len(self.content) == 0:
  1226.                     current_style = style.copy()
  1227.                 
  1228.                 name = action[0]
  1229.                 val = LRFObject.tag_to_val(action, self, tag, None)
  1230.                 if name and current_style[name] != val:
  1231.                     if len(self.content) > 0 and isinstance(self.content[-1], self.__class__.Span):
  1232.                         self.content[-1].attrs[name] = val
  1233.                     else:
  1234.                         self.content.append(self.__class__.Span('Span', {
  1235.                             name: val }))
  1236.                     current_style[name] = val
  1237.                 
  1238.             current_style[name] != val
  1239.         if len(self.content) > 0:
  1240.             self.close_containers()
  1241.         
  1242.         self.stream = None
  1243.  
  1244.     
  1245.     def __unicode__(self):
  1246.         s = u''
  1247.         open_containers = collections.deque()
  1248.         for c in self.content:
  1249.             if isinstance(c, basestring):
  1250.                 s += prepare_string_for_xml(c).replace('\x00', '')
  1251.                 continue
  1252.             if c is None:
  1253.                 if open_containers:
  1254.                     p = open_containers.pop()
  1255.                     s += u'</%s>' % (p.name,)
  1256.                 
  1257.             open_containers
  1258.             s += unicode(c)
  1259.             if not c.self_closing:
  1260.                 open_containers.append(c)
  1261.                 continue
  1262.         
  1263.         if len(open_containers) > 0:
  1264.             if len(open_containers) == 1:
  1265.                 s += u'</%s>' % (open_containers[0].name,)
  1266.             else:
  1267.                 raise []([] % (_[1],))
  1268.         len(open_containers) == 1
  1269.         return s
  1270.  
  1271.     
  1272.     def to_html(self):
  1273.         s = u''
  1274.         open_containers = collections.deque()
  1275.         in_p = False
  1276.         for c in self.content:
  1277.             if isinstance(c, basestring):
  1278.                 s += c
  1279.                 continue
  1280.             if c is None:
  1281.                 if c.name == 'P':
  1282.                     in_p = False
  1283.                 
  1284.                 p = open_containers.pop()
  1285.                 s += p.close_html()
  1286.                 continue
  1287.             if c.name == 'P':
  1288.                 in_p = True
  1289.                 continue
  1290.             if c.name == 'CR':
  1291.                 None += s if in_p else '<p>'
  1292.                 continue
  1293.             s += c.to_html()
  1294.             if not c.self_closing:
  1295.                 open_containers.append(c)
  1296.                 continue
  1297.         
  1298.         if len(open_containers) > 0:
  1299.             raise []([] % (_[1],))
  1300.         len(open_containers) > 0
  1301.         return s
  1302.  
  1303.  
  1304.  
  1305. class Image(LRFObject):
  1306.     tag_map = {
  1307.         62794: [
  1308.             '',
  1309.             'parse_image_rect'],
  1310.         62795: [
  1311.             '',
  1312.             'parse_image_size'],
  1313.         62796: [
  1314.             'refstream',
  1315.             'D'],
  1316.         62805: [
  1317.             'comment',
  1318.             'P'] }
  1319.     
  1320.     def parse_image_rect(self, tag, f):
  1321.         (self.x0, self.y0, self.x1, self.y1) = struct.unpack('<HHHH', tag.contents)
  1322.  
  1323.     
  1324.     def parse_image_size(self, tag, f):
  1325.         (self.xsize, self.ysize) = struct.unpack('<HH', tag.contents)
  1326.  
  1327.     encoding = property(fget = (lambda self: self._document.objects[self.refstream].encoding))
  1328.     data = property(fget = (lambda self: self._document.objects[self.refstream].stream))
  1329.     
  1330.     def __unicode__(self):
  1331.         return u'<Image objid="%s" x0="%d" y0="%d" x1="%d" y1="%d" xsize="%d" ysize="%d" refstream="%d" />\n' % (self.id, self.x0, self.y0, self.x1, self.y1, self.xsize, self.ysize, self.refstream)
  1332.  
  1333.  
  1334.  
  1335. class PutObj(EmptyPageElement):
  1336.     
  1337.     def __init__(self, objects, x1, y1, refobj):
  1338.         self.x1 = x1
  1339.         self.y1 = y1
  1340.         self.refobj = refobj
  1341.         self.object = objects[refobj]
  1342.  
  1343.     
  1344.     def __unicode__(self):
  1345.         return u'<PutObj x1="%d" y1="%d" refobj="%d" />' % (self.x1, self.y1, self.refobj)
  1346.  
  1347.  
  1348.  
  1349. class Canvas(LRFStream):
  1350.     tag_map = {
  1351.         62801: [
  1352.             'canvaswidth',
  1353.             'W'],
  1354.         62802: [
  1355.             'canvasheight',
  1356.             'W'],
  1357.         62938: [
  1358.             '',
  1359.             'parse_waits'],
  1360.         62771: [
  1361.             'blockrule',
  1362.             'W',
  1363.             {
  1364.                 68: 'block-fixed',
  1365.                 34: 'block-adjustable' }],
  1366.         62772: [
  1367.             'bgcolor',
  1368.             'D',
  1369.             Color],
  1370.         62773: [
  1371.             'layout',
  1372.             'W',
  1373.             {
  1374.                 65: 'TbRl',
  1375.                 52: 'LrTb' }],
  1376.         62774: [
  1377.             'framewidth',
  1378.             'W'],
  1379.         62775: [
  1380.             'framecolor',
  1381.             'D',
  1382.             Color],
  1383.         62766: [
  1384.             'framemode',
  1385.             'W',
  1386.             {
  1387.                 0: 'none',
  1388.                 2: 'curve',
  1389.                 1: 'square' }] }
  1390.     tag_map.update(LRFStream.tag_map)
  1391.     extra_attrs = [
  1392.         'canvaswidth',
  1393.         'canvasheight',
  1394.         'blockrule',
  1395.         'layout',
  1396.         'framewidth',
  1397.         'framecolor',
  1398.         'framemode']
  1399.     
  1400.     def parse_waits(self, tag, f):
  1401.         val = tag.word
  1402.         self.setwaitprop = val & 15
  1403.         self.setwaitsync = val & 240
  1404.  
  1405.     
  1406.     def initialize(self):
  1407.         self.attrs = { }
  1408.         for attr in self.extra_attrs:
  1409.             if hasattr(self, attr):
  1410.                 self.attrs[attr] = getattr(self, attr)
  1411.                 continue
  1412.         
  1413.         self._contents = []
  1414.         stream = cStringIO.StringIO(self.stream)
  1415.         while stream.tell() < len(self.stream):
  1416.             tag = Tag(stream)
  1417.             
  1418.             try:
  1419.                 self._contents.append(PutObj(self._document.objects, *struct.unpack('<HHI', tag.contents)))
  1420.             continue
  1421.             except struct.error:
  1422.                 print 'Canvas object has errors, skipping.'
  1423.                 continue
  1424.             
  1425.  
  1426.             None<EXCEPTION MATCH>struct.error
  1427.  
  1428.     
  1429.     def __unicode__(self):
  1430.         s = '\n<%s objid="%s" ' % (self.__class__.__name__, self.id)
  1431.         for attr in self.attrs:
  1432.             s += '%s="%s" ' % (attr, self.attrs[attr])
  1433.         
  1434.         s = s.rstrip() + '>\n'
  1435.         for po in self:
  1436.             s += unicode(po) + '\n'
  1437.         
  1438.         s += '</%s>\n' % (self.__class__.__name__,)
  1439.         return s
  1440.  
  1441.     
  1442.     def __iter__(self):
  1443.         for i in self._contents:
  1444.             yield i
  1445.         
  1446.  
  1447.  
  1448.  
  1449. class Header(Canvas):
  1450.     pass
  1451.  
  1452.  
  1453. class Footer(Canvas):
  1454.     pass
  1455.  
  1456.  
  1457. class ESound(LRFObject):
  1458.     pass
  1459.  
  1460.  
  1461. class ImageStream(LRFStream):
  1462.     tag_map = {
  1463.         62805: [
  1464.             'comment',
  1465.             'P'] }
  1466.     imgext = {
  1467.         17: 'jpeg',
  1468.         18: 'png',
  1469.         19: 'bmp',
  1470.         20: 'gif' }
  1471.     tag_map.update(LRFStream.tag_map)
  1472.     encoding = property(fget = (lambda self: self.imgext[self.stream_flags & 255].upper()))
  1473.     
  1474.     def end_stream(self, *args):
  1475.         LRFStream.end_stream(self, *args)
  1476.         self.file = str(self.id) + '.' + self.encoding.lower()
  1477.         if self._document is not None:
  1478.             self._document.image_map[self.id] = self
  1479.         
  1480.  
  1481.     
  1482.     def __unicode__(self):
  1483.         return u'<ImageStream objid="%s" encoding="%s" file="%s" />\n' % (self.id, self.encoding, self.file)
  1484.  
  1485.  
  1486.  
  1487. class Import(LRFStream):
  1488.     pass
  1489.  
  1490.  
  1491. class Button(LRFObject):
  1492.     tag_map = {
  1493.         62723: [
  1494.             '',
  1495.             'do_ref_image'],
  1496.         62817: [
  1497.             'button_flags',
  1498.             'W'],
  1499.         62818: [
  1500.             '',
  1501.             'do_base_button'],
  1502.         62819: [
  1503.             '',
  1504.             ''],
  1505.         62820: [
  1506.             '',
  1507.             'do_focus_in_button'],
  1508.         62821: [
  1509.             '',
  1510.             ''],
  1511.         62822: [
  1512.             '',
  1513.             'do_push_button'],
  1514.         62823: [
  1515.             '',
  1516.             ''],
  1517.         62824: [
  1518.             '',
  1519.             'do_up_button'],
  1520.         62825: [
  1521.             '',
  1522.             ''],
  1523.         62826: [
  1524.             '',
  1525.             'do_start_actions'],
  1526.         62827: [
  1527.             '',
  1528.             ''],
  1529.         62828: [
  1530.             '',
  1531.             'parse_jump_to'],
  1532.         62829: [
  1533.             '',
  1534.             'parse_send_message'],
  1535.         62830: [
  1536.             '',
  1537.             'parse_close_window'],
  1538.         62934: [
  1539.             '',
  1540.             'parse_sound_stop'],
  1541.         62969: [
  1542.             '',
  1543.             'parse_run'] }
  1544.     tag_map.update(LRFObject.tag_map)
  1545.     
  1546.     def __init__(self, document, stream, id, scramble_key, boundary):
  1547.         self.xml = u''
  1548.         self.refimage = { }
  1549.         self.actions = { }
  1550.         self.to_dump = True
  1551.         LRFObject.__init__(self, document, stream, id, scramble_key, boundary)
  1552.  
  1553.     
  1554.     def do_ref_image(self, tag, f):
  1555.         self.refimage[self.button_type] = tag.dword
  1556.  
  1557.     
  1558.     def do_base_button(self, tag, f):
  1559.         self.button_type = 0
  1560.         self.actions[self.button_type] = []
  1561.  
  1562.     
  1563.     def do_focus_in_button(self, tag, f):
  1564.         self.button_type = 1
  1565.  
  1566.     
  1567.     def do_push_button(self, tag, f):
  1568.         self.button_type = 2
  1569.  
  1570.     
  1571.     def do_up_button(self, tag, f):
  1572.         self.button_type = 3
  1573.  
  1574.     
  1575.     def do_start_actions(self, tag, f):
  1576.         self.actions[self.button_type] = []
  1577.  
  1578.     
  1579.     def parse_jump_to(self, tag, f):
  1580.         self.actions[self.button_type].append((1, struct.unpack('<II', tag.contents)))
  1581.  
  1582.     
  1583.     def parse_send_message(self, tag, f):
  1584.         params = (tag.word, Tag.string_parser(f), Tag.string_parser(f))
  1585.         self.actions[self.button_type].append((2, params))
  1586.  
  1587.     
  1588.     def parse_close_window(self, tag, f):
  1589.         self.actions[self.button_type].append((3,))
  1590.  
  1591.     
  1592.     def parse_sound_stop(self, tag, f):
  1593.         self.actions[self.button_type].append((4,))
  1594.  
  1595.     
  1596.     def parse_run(self, tag, f):
  1597.         self.actions[self.button_type].append((5, struct.unpack('<HI', tag.contents)))
  1598.  
  1599.     
  1600.     def jump_action(self, button_type):
  1601.         for i in self.actions[button_type]:
  1602.             if i[0] == 1:
  1603.                 return i[1:][0]
  1604.         
  1605.         return (None, None)
  1606.  
  1607.     
  1608.     def __unicode__(self):
  1609.         s = u'<Button objid="%s">\n' % (self.id,)
  1610.         if self.button_flags & 16 != 0:
  1611.             s += '<PushButton '
  1612.             if 2 in self.refimage:
  1613.                 s += 'refimage="%s" ' % (self.refimage[2],)
  1614.             
  1615.             s = s.rstrip() + '>\n'
  1616.             s += '<JumpTo refpage="%s" refobj="%s" />\n' % self.jump_action(2)
  1617.             s += '</PushButton>\n'
  1618.         else:
  1619.             raise LRFParseError('Unsupported button type')
  1620.         (self.button_flags & 16 != 0) += '</Button>\n'
  1621.         return s
  1622.  
  1623.     refpage = property(fget = (lambda self: self.jump_action(2)[0]))
  1624.     refobj = property(fget = (lambda self: self.jump_action(2)[1]))
  1625.  
  1626.  
  1627. class Window(LRFObject):
  1628.     pass
  1629.  
  1630.  
  1631. class PopUpWin(LRFObject):
  1632.     pass
  1633.  
  1634.  
  1635. class Sound(LRFObject):
  1636.     pass
  1637.  
  1638.  
  1639. class SoundStream(LRFObject):
  1640.     pass
  1641.  
  1642.  
  1643. class Font(LRFStream):
  1644.     tag_map = {
  1645.         62809: [
  1646.             'fontfilename',
  1647.             'P'],
  1648.         62813: [
  1649.             'fontfacename',
  1650.             'P'] }
  1651.     tag_map.update(LRFStream.tag_map)
  1652.     data = property(fget = (lambda self: self.stream))
  1653.     
  1654.     def end_stream(self, *args):
  1655.         LRFStream.end_stream(self, *args)
  1656.         self._document.font_map[self.fontfacename] = self
  1657.         self.file = self.fontfacename + '.ttf'
  1658.  
  1659.     
  1660.     def __unicode__(self):
  1661.         s = '<RegistFont objid="%s" fontfilename="%s" fontname="%s" encoding="TTF" file="%s" />\n' % (self.id, self.fontfilename, self.fontfacename, self.file)
  1662.         return s
  1663.  
  1664.  
  1665.  
  1666. class ObjectInfo(LRFStream):
  1667.     pass
  1668.  
  1669.  
  1670. class BookAttr(StyleObject, LRFObject):
  1671.     tag_map = {
  1672.         62843: [
  1673.             'page_tree_id',
  1674.             'D'],
  1675.         62936: [
  1676.             '',
  1677.             'add_font'],
  1678.         62938: [
  1679.             'setwaitprop',
  1680.             'W',
  1681.             {
  1682.                 1: 'replay',
  1683.                 2: 'noreplay' }] }
  1684.     tag_map.update(ruby_tags)
  1685.     tag_map.update(LRFObject.tag_map)
  1686.     binding_map = {
  1687.         1: 'Lr',
  1688.         16: 'Rl' }
  1689.     
  1690.     def __init__(self, document, stream, id, scramble_key, boundary):
  1691.         self.font_link_list = []
  1692.         LRFObject.__init__(self, document, stream, id, scramble_key, boundary)
  1693.  
  1694.     
  1695.     def add_font(self, tag, f):
  1696.         self.font_link_list.append(tag.dword)
  1697.  
  1698.     
  1699.     def __unicode__(self):
  1700.         s = u'<BookStyle objid="%s" stylelabel="%s">\n' % (self.id, self.id)
  1701.         s += u'<SetDefault %s />\n' % (self._tags_to_xml(),)
  1702.         doc = self._document
  1703.         s += u'<BookSetting bindingdirection="%s" dpi="%s" screenwidth="%s" screenheight="%s" colordepth="%s" />\n' % (self.binding_map[doc.binding], doc.dpi, doc.width, doc.height, doc.color_depth)
  1704.         for font in self._document.font_map.values():
  1705.             s += unicode(font)
  1706.         
  1707.         s += '</BookStyle>\n'
  1708.         return s
  1709.  
  1710.  
  1711.  
  1712. class SimpleText(Text):
  1713.     pass
  1714.  
  1715.  
  1716. class TocLabel(object):
  1717.     
  1718.     def __init__(self, refpage, refobject, label):
  1719.         self.refpage = refpage
  1720.         self.refobject = refobject
  1721.         self.label = label
  1722.  
  1723.     
  1724.     def __unicode__(self):
  1725.         return u'<TocLabel refpage="%s" refobj="%s">%s</TocLabel>\n' % (self.refpage, self.refobject, self.label)
  1726.  
  1727.  
  1728.  
  1729. class TOCObject(LRFStream):
  1730.     
  1731.     def initialize(self):
  1732.         stream = cStringIO.StringIO(self.stream)
  1733.         c = struct.unpack('<H', stream.read(2))[0]
  1734.         stream.seek(4 * (c + 1))
  1735.         self._contents = []
  1736.         while c > 0:
  1737.             refpage = struct.unpack('<I', stream.read(4))[0]
  1738.             refobj = struct.unpack('<I', stream.read(4))[0]
  1739.             cnt = struct.unpack('<H', stream.read(2))[0]
  1740.             raw = stream.read(cnt)
  1741.             label = raw.decode('utf_16_le')
  1742.             self._contents.append(TocLabel(refpage, refobj, label))
  1743.             c -= 1
  1744.  
  1745.     
  1746.     def __iter__(self):
  1747.         for i in self._contents:
  1748.             yield i
  1749.         
  1750.  
  1751.     
  1752.     def __unicode__(self):
  1753.         s = u'<TOC>\n'
  1754.         for i in self:
  1755.             s += unicode(i)
  1756.         
  1757.         return s + '</TOC>\n'
  1758.  
  1759.  
  1760. object_map = [
  1761.     None,
  1762.     PageTree,
  1763.     Page,
  1764.     Header,
  1765.     Footer,
  1766.     PageAttr,
  1767.     Block,
  1768.     BlockAttr,
  1769.     MiniPage,
  1770.     None,
  1771.     Text,
  1772.     TextAttr,
  1773.     Image,
  1774.     Canvas,
  1775.     ESound,
  1776.     None,
  1777.     None,
  1778.     ImageStream,
  1779.     Import,
  1780.     Button,
  1781.     Window,
  1782.     PopUpWin,
  1783.     Sound,
  1784.     SoundStream,
  1785.     None,
  1786.     Font,
  1787.     ObjectInfo,
  1788.     None,
  1789.     BookAttr,
  1790.     SimpleText,
  1791.     TOCObject]
  1792.  
  1793. def get_object(document, stream, id, offset, size, scramble_key):
  1794.     stream.seek(offset)
  1795.     start_tag = Tag(stream)
  1796.     if start_tag.id != 62720:
  1797.         raise LRFParseError('Bad object start')
  1798.     start_tag.id != 62720
  1799.     (obj_id, obj_type) = struct.unpack('<IH', start_tag.contents)
  1800.     if obj_type < len(object_map) and object_map[obj_type] is not None:
  1801.         return object_map[obj_type](document, stream, obj_id, scramble_key, offset + size - Tag.tags[0][0])
  1802.     raise LRFParseError('Unknown object type: %02X!' % obj_type)
  1803.  
  1804.