home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / calibre-0.7.26.msi / file_1064 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-10-31  |  16.4 KB  |  568 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2009, John Schember <john@nachtimwald.com>'
  6. __docformat__ = 'restructuredtext en'
  7. import os
  8. import re
  9. import StringIO
  10. from calibre import my_unichr, prepare_string_for_xml
  11. from calibre.ebooks.metadata.toc import TOC
  12.  
  13. class PML_HTMLizer(object):
  14.     STATES = [
  15.         'i',
  16.         'u',
  17.         'd',
  18.         'b',
  19.         'sp',
  20.         'sb',
  21.         'h1',
  22.         'h2',
  23.         'h3',
  24.         'h4',
  25.         'h5',
  26.         'h6',
  27.         'a',
  28.         'ra',
  29.         'c',
  30.         'r',
  31.         't',
  32.         's',
  33.         'l',
  34.         'k',
  35.         'T',
  36.         'FN',
  37.         'SB']
  38.     STATES_VALUE_REQ = [
  39.         'a',
  40.         'T',
  41.         'FN',
  42.         'SB']
  43.     STATES_VALUE_REQ_2 = [
  44.         'ra']
  45.     STATES_CLOSE_VALUE_REQ = [
  46.         'FN',
  47.         'SB']
  48.     STATES_TAGS = {
  49.         'h1': ('<h1 style="page-break-before: always;">', '</h1>'),
  50.         'h2': ('<h2>', '</h2>'),
  51.         'h3': ('<h3>', '</h3>'),
  52.         'h4': ('<h4>', '</h4>'),
  53.         'h5': ('<h5>', '</h5>'),
  54.         'h6': ('<h6>', '</h6>'),
  55.         'sp': ('<sup>', '</sup>'),
  56.         'sb': ('<sub>', '</sub>'),
  57.         'a': ('<a href="#%s">', '</a>'),
  58.         'ra': ('<span id="r%s"></span><a href="#%s">', '</a>'),
  59.         'c': ('<div style="text-align: center; margin: auto;">', '</div>'),
  60.         'r': ('<div style="text-align: right;">', '</div>'),
  61.         't': ('<div style="text-indent: 5%;">', '</div>'),
  62.         'T': ('<div style="text-indent: %s;">', '</div>'),
  63.         'i': ('<span style="font-style: italic;">', '</span>'),
  64.         'u': ('<span style="text-decoration: underline;">', '</span>'),
  65.         'd': ('<span style="text-decoration: line-through;">', '</span>'),
  66.         'b': ('<span style="font-weight: bold;">', '</span>'),
  67.         'l': ('<span style="font-size: 150%;">', '</span>'),
  68.         'k': ('<span style="font-size: 75%; font-variant: small-caps;">', '</span>'),
  69.         'FN': ('<br /><br style="page-break-after: always;" /><div id="fn-%s"><p>', '</p><<small><a href="#rfn-%s">return</a></small></div>'),
  70.         'SB': ('<br /><br style="page-break-after: always;" /><div id="sb-%s"><p>', '</p><small><a href="#rsb-%s">return</a></small></div>') }
  71.     CODE_STATES = {
  72.         'q': 'a',
  73.         'x': 'h1',
  74.         'X0': 'h2',
  75.         'X1': 'h3',
  76.         'X2': 'h4',
  77.         'X3': 'h5',
  78.         'X4': 'h6',
  79.         'Sp': 'sp',
  80.         'Sb': 'sb',
  81.         'c': 'c',
  82.         'r': 'r',
  83.         't': 't',
  84.         'T': 'T',
  85.         'i': 'i',
  86.         'I': 'i',
  87.         'u': 'u',
  88.         'o': 'd',
  89.         'b': 'b',
  90.         'B': 'b',
  91.         'l': 'l',
  92.         'k': 'k',
  93.         'Fn': 'ra',
  94.         'Sd': 'ra',
  95.         'FN': 'FN',
  96.         'SB': 'SB' }
  97.     LINK_STATES = [
  98.         'a',
  99.         'ra']
  100.     BLOCK_STATES = [
  101.         'a',
  102.         'ra',
  103.         'h1',
  104.         'h2',
  105.         'h3',
  106.         'h4',
  107.         'h5',
  108.         'h6',
  109.         'sb',
  110.         'sp']
  111.     DIV_STATES = [
  112.         'c',
  113.         'r',
  114.         't',
  115.         'T',
  116.         'FN',
  117.         'SB']
  118.     SPAN_STATES = [
  119.         'l',
  120.         'k',
  121.         'i',
  122.         'u',
  123.         'd',
  124.         'b']
  125.     
  126.     def __init__(self):
  127.         self.state = { }
  128.         self.toc = TOC()
  129.         self.file_name = ''
  130.  
  131.     
  132.     def prepare_pml(self, pml):
  133.         pml = re.sub(('(?<=\\\\x)(?P<text>.*?)(?=\\\\x)',), (lambda match: '="%s"%s' % (self.strip_pml(match.group('text')), match.group('text'))), pml)
  134.         pml = re.sub(('(?<=\\\\X[0-4])(?P<text>.*?)(?=\\\\X[0-4])',), (lambda match: '="%s"%s' % (self.strip_pml(match.group('text')), match.group('text'))), pml)
  135.         pml = re.sub('(?mus)\\\\v(?P<text>.*?)\\\\v', '', pml)
  136.         pml = re.sub('(?mus)[ ]{2,}', ' ', pml)
  137.         pml = re.sub('(?mus)^[ ]*(?=.)', '', pml)
  138.         pml = re.sub('(?mus)(?<=.)[ ]*$', '', pml)
  139.         pml = re.sub('(?mus)^[ ]*$', '', pml)
  140.         pml = re.sub('(?mus)<footnote\\s+id="(?P<target>.+?)">\\s*(?P<text>.*?)\\s*</footnote>', (lambda match: if match.group('text'):
  141. '\\FN="%s"%s\\FN' % (match.group('target'), match.group('text'))''), pml)
  142.         pml = re.sub('(?mus)<sidebar\\s+id="(?P<target>.+?)">\\s*(?P<text>.*?)\\s*</sidebar>', (lambda match: if match.group('text'):
  143. '\\SB="%s"%s\\SB' % (match.group('target'), match.group('text'))''), pml)
  144.         pml = pml.replace('&', '&')
  145.         pml = re.sub('\\\\a(?P<num>\\d{3})', (lambda match: '&#%s;' % match.group('num')), pml)
  146.         pml = re.sub('\\\\U(?P<num>[0-9a-f]{4})', (lambda match: '%s' % my_unichr(int(match.group('num'), 16))), pml)
  147.         pml = prepare_string_for_xml(pml)
  148.         return pml
  149.  
  150.     
  151.     def strip_pml(self, pml):
  152.         pml = re.sub('\\\\C\\d=".*"', '', pml)
  153.         pml = re.sub('\\\\Fn=".*"', '', pml)
  154.         pml = re.sub('\\\\Sd=".*"', '', pml)
  155.         pml = re.sub('\\\\.=".*"', '', pml)
  156.         pml = re.sub('\\\\X\\d', '', pml)
  157.         pml = re.sub('\\\\S[pbd]', '', pml)
  158.         pml = re.sub('\\\\Fn', '', pml)
  159.         pml = re.sub('\\\\a\\d\\d\\d', '', pml)
  160.         pml = re.sub('\\\\U\\d\\d\\d\\d', '', pml)
  161.         pml = re.sub('\\\\.', '', pml)
  162.         pml.replace('\r\n', ' ')
  163.         pml.replace('\n', ' ')
  164.         pml.replace('\r', ' ')
  165.         return pml
  166.  
  167.     
  168.     def cleanup_html(self, html):
  169.         old = html
  170.         html = self.cleanup_html_remove_redundant(html)
  171.         while html != old:
  172.             old = html
  173.             html = self.cleanup_html_remove_redundant(html)
  174.         html = re.sub('(?imu)^\\s*', '', html)
  175.         return html
  176.  
  177.     
  178.     def cleanup_html_remove_redundant(self, html):
  179.         for key in self.STATES_TAGS.keys():
  180.             (open, close) = self.STATES_TAGS[key]
  181.             if key in self.STATES_VALUE_REQ:
  182.                 html = re.sub('(?u)%s\\s*%s' % (open % '.*?', close), '', html)
  183.                 continue
  184.             html = re.sub('(?u)%s\\s*%s' % (open, close), '', html)
  185.         
  186.         html = re.sub('(?imu)<p>\\s*</p>', '', html)
  187.         return html
  188.  
  189.     
  190.     def start_line(self):
  191.         start = u''
  192.         div = []
  193.         span = []
  194.         other = []
  195.         for key, val in self.state.items():
  196.             if val[0]:
  197.                 if key in self.DIV_STATES:
  198.                     div.append((key, val[1]))
  199.                 elif key in self.SPAN_STATES:
  200.                     span.append((key, val[1]))
  201.                 else:
  202.                     other.append((key, val[1]))
  203.             key in self.DIV_STATES
  204.         
  205.         for key, val in other + div + span:
  206.             if key in self.STATES_VALUE_REQ:
  207.                 start += self.STATES_TAGS[key][0] % val
  208.                 continue
  209.             if key in self.STATES_VALUE_REQ_2:
  210.                 start += self.STATES_TAGS[key][0] % (val, val)
  211.                 continue
  212.             start += self.STATES_TAGS[key][0]
  213.         
  214.         return u'<p>%s' % start
  215.  
  216.     
  217.     def end_line(self):
  218.         end = u''
  219.         div = []
  220.         span = []
  221.         other = []
  222.         for key, val in self.state.items():
  223.             if val[0]:
  224.                 if key == 'T':
  225.                     self.state['T'][0] = False
  226.                 
  227.                 if key in self.DIV_STATES:
  228.                     div.append(key)
  229.                 elif key in self.SPAN_STATES:
  230.                     span.append(key)
  231.                 else:
  232.                     other.append(key)
  233.             key in self.DIV_STATES
  234.         
  235.         for key in span + div + other:
  236.             if key in self.STATES_CLOSE_VALUE_REQ:
  237.                 end += self.STATES_TAGS[key][1] % self.state[key][1]
  238.                 continue
  239.             end += self.STATES_TAGS[key][1]
  240.         
  241.         return u'%s</p>' % end
  242.  
  243.     
  244.     def process_code(self, code, stream, pre = ''):
  245.         text = u''
  246.         code = self.CODE_STATES.get(code, None)
  247.         if not code:
  248.             return text
  249.         if code in self.DIV_STATES:
  250.             if code == 'T' and self.state['T'][0]:
  251.                 self.code_value(stream)
  252.                 return text
  253.             text = self.process_code_div(code, stream)
  254.         elif code in self.SPAN_STATES:
  255.             text = self.process_code_span(code, stream)
  256.         elif code in self.BLOCK_STATES:
  257.             text = self.process_code_block(code, stream, pre)
  258.         else:
  259.             text = self.process_code_simple(code, stream)
  260.         self.state[code][0] = not self.state[code][0]
  261.         return text
  262.  
  263.     
  264.     def process_code_simple(self, code, stream):
  265.         text = u''
  266.         if self.state[code][0]:
  267.             if code in self.STATES_CLOSE_VALUE_REQ:
  268.                 text = self.STATES_TAGS[code][1] % self.state[code][1]
  269.             else:
  270.                 text = self.STATES_TAGS[code][1]
  271.         elif code in self.STATES_VALUE_REQ or code in self.STATES_VALUE_REQ_2:
  272.             val = self.code_value(stream)
  273.             if code in self.STATES_VALUE_REQ:
  274.                 text = self.STATES_TAGS[code][0] % val
  275.             else:
  276.                 text = self.STATES_TAGS[code][0] % (val, val)
  277.             self.state[code][1] = val
  278.         else:
  279.             text = self.STATES_TAGS[code][0]
  280.         return text
  281.  
  282.     
  283.     def process_code_div(self, code, stream):
  284.         text = u''
  285.         if self.state[code][0]:
  286.             for c in self.SPAN_STATES + self.DIV_STATES:
  287.                 if self.state[c][0]:
  288.                     if c in self.STATES_CLOSE_VALUE_REQ:
  289.                         text += self.STATES_TAGS[c][1] % self.state[c][1]
  290.                     else:
  291.                         text += self.STATES_TAGS[c][1]
  292.                 c in self.STATES_CLOSE_VALUE_REQ
  293.             
  294.             for c in self.DIV_STATES + self.SPAN_STATES:
  295.                 if code == c:
  296.                     continue
  297.                 
  298.                 if self.state[c][0]:
  299.                     if c in self.STATES_VALUE_REQ:
  300.                         text += self.STATES_TAGS[self.CODE_STATES[c]][0] % self.state[c][1]
  301.                     elif c in self.STATES_VALUE_REQ_2:
  302.                         text += self.STATES_TAGS[self.CODE_STATES[c]][0] % (self.state[c][1], self.state[c][1])
  303.                     else:
  304.                         text += self.STATES_TAGS[c][0]
  305.                 c in self.STATES_VALUE_REQ
  306.             
  307.         else:
  308.             for c in self.SPAN_STATES:
  309.                 if self.state[c][0]:
  310.                     if c in self.STATES_CLOSE_VALUE_REQ:
  311.                         text += self.STATES_TAGS[c][1] % self.state[c][1]
  312.                     else:
  313.                         text += self.STATES_TAGS[c][1]
  314.                 c in self.STATES_CLOSE_VALUE_REQ
  315.             
  316.             if code in self.STATES_VALUE_REQ or code in self.STATES_VALUE_REQ_2:
  317.                 val = self.code_value(stream)
  318.                 if code in self.STATES_VALUE_REQ:
  319.                     text += self.STATES_TAGS[code][0] % val
  320.                 else:
  321.                     text += self.STATES_TAGS[code][0] % (val, val)
  322.                 self.state[code][1] = val
  323.             else:
  324.                 text += self.STATES_TAGS[code][0]
  325.             for c in self.SPAN_STATES:
  326.                 if self.state[c][0]:
  327.                     if c in self.STATES_VALUE_REQ:
  328.                         text += self.STATES_TAGS[self.CODE_STATES[c]][0] % self.state[c][1]
  329.                     elif c in self.STATES_VALUE_REQ_2:
  330.                         text += self.STATES_TAGS[self.CODE_STATES[c]][0] % (self.state[c][1], self.state[c][1])
  331.                     else:
  332.                         text += self.STATES_TAGS[c][0]
  333.                 c in self.STATES_VALUE_REQ
  334.             
  335.         return text
  336.  
  337.     
  338.     def process_code_span(self, code, stream):
  339.         text = u''
  340.         if self.state[code][0]:
  341.             for c in self.SPAN_STATES:
  342.                 if self.state[c][0]:
  343.                     if c in self.STATES_CLOSE_VALUE_REQ:
  344.                         text += self.STATES_TAGS[c][1] % self.state[c][1]
  345.                     else:
  346.                         text += self.STATES_TAGS[c][1]
  347.                 c in self.STATES_CLOSE_VALUE_REQ
  348.             
  349.             for c in self.SPAN_STATES:
  350.                 if code == c:
  351.                     continue
  352.                 
  353.                 if self.state[c][0]:
  354.                     if c in self.STATES_VALUE_REQ:
  355.                         text += self.STATES_TAGS[code][0] % self.state[c][1]
  356.                     elif c in self.STATES_VALUE_REQ_2:
  357.                         text += self.STATES_TAGS[code][0] % (self.state[c][1], self.state[c][1])
  358.                     else:
  359.                         text += self.STATES_TAGS[c][0]
  360.                 c in self.STATES_VALUE_REQ
  361.             
  362.         elif code in self.STATES_VALUE_REQ or code in self.STATES_VALUE_REQ_2:
  363.             val = self.code_value(stream)
  364.             if code in self.STATES_VALUE_REQ:
  365.                 text += self.STATES_TAGS[code][0] % val
  366.             else:
  367.                 text += self.STATES_TAGS[code][0] % (val, val)
  368.             self.state[code][1] = val
  369.         else:
  370.             text += self.STATES_TAGS[code][0]
  371.         return text
  372.  
  373.     
  374.     def process_code_block(self, code, stream, pre = ''):
  375.         text = u''
  376.         for c in self.SPAN_STATES:
  377.             if self.state[c][0]:
  378.                 if c in self.STATES_CLOSE_VALUE_REQ:
  379.                     text += self.STATES_TAGS[c][1] % self.state[c][1]
  380.                 else:
  381.                     text += self.STATES_TAGS[c][1]
  382.             c in self.STATES_CLOSE_VALUE_REQ
  383.         
  384.         if self.state[code][0]:
  385.             if code in self.STATES_CLOSE_VALUE_REQ:
  386.                 text += self.STATES_TAGS[code][1] % self.state[code][1]
  387.             else:
  388.                 text += self.STATES_TAGS[code][1]
  389.         elif code in self.STATES_VALUE_REQ or code in self.STATES_VALUE_REQ_2:
  390.             val = self.code_value(stream)
  391.             if code in self.LINK_STATES:
  392.                 val = val.lstrip('#')
  393.             
  394.             if pre:
  395.                 val = '%s-%s' % (pre, val)
  396.             
  397.             if code in self.STATES_VALUE_REQ:
  398.                 text += self.STATES_TAGS[code][0] % val
  399.             else:
  400.                 text += self.STATES_TAGS[code][0] % (val, val)
  401.             self.state[code][1] = val
  402.         else:
  403.             text += self.STATES_TAGS[code][0]
  404.         for c in self.SPAN_STATES:
  405.             if self.state[c][0]:
  406.                 if c in self.STATES_VALUE_REQ:
  407.                     text += self.STATES_TAGS[code][0] % self.state[c][1]
  408.                 elif c in self.STATES_VALUE_REQ_2:
  409.                     text += self.STATES_TAGS[code][0] % (self.state[c][1], self.state[c][1])
  410.                 else:
  411.                     text += self.STATES_TAGS[c][0]
  412.             c in self.STATES_VALUE_REQ
  413.         
  414.         return text
  415.  
  416.     
  417.     def code_value(self, stream):
  418.         value = u''
  419.         state = 0
  420.         loc = stream.tell()
  421.         c = stream.read(1)
  422.         while c != '':
  423.             if state == 0:
  424.                 if c == '=':
  425.                     state = 1
  426.                 elif c != ' ':
  427.                     break
  428.                 
  429.             elif state == 1:
  430.                 if c == '"':
  431.                     state = 2
  432.                 elif c != ' ':
  433.                     break
  434.                 
  435.             elif state == 2:
  436.                 if c == '"':
  437.                     state = 3
  438.                     break
  439.                 else:
  440.                     value += c
  441.             
  442.             c = stream.read(1)
  443.         if state != 3:
  444.             stream.seek(loc)
  445.             value = u''
  446.         
  447.         return value.strip()
  448.  
  449.     
  450.     def parse_pml(self, pml, file_name = ''):
  451.         pml = self.prepare_pml(pml)
  452.         output = []
  453.         self.state = { }
  454.         self.toc = TOC()
  455.         self.file_name = file_name
  456.         for s in self.STATES:
  457.             self.state[s] = [
  458.                 False,
  459.                 '']
  460.         
  461.         for line in pml.splitlines():
  462.             if not line:
  463.                 continue
  464.             
  465.             parsed = []
  466.             empty = True
  467.             line = StringIO.StringIO(line)
  468.             parsed.append(self.start_line())
  469.             c = line.read(1)
  470.             while c != '':
  471.                 text = u''
  472.                 if c == '\\':
  473.                     c = line.read(1)
  474.                     if c in 'qcrtTiIuobBlk':
  475.                         text = self.process_code(c, line)
  476.                     elif c in 'FS':
  477.                         l = line.read(1)
  478.                         if '%s%s' % (c, l) == 'Fn':
  479.                             text = self.process_code('Fn', line, 'fn')
  480.                         elif '%s%s' % (c, l) == 'FN':
  481.                             text = self.process_code('FN', line)
  482.                         elif '%s%s' % (c, l) == 'SB':
  483.                             text = self.process_code('SB', line)
  484.                         elif '%s%s' % (c, l) == 'Sd':
  485.                             text = self.process_code('Sd', line, 'sb')
  486.                         
  487.                     elif c in 'xXC':
  488.                         empty = False
  489.                         t = ''
  490.                         if c in 'XC':
  491.                             level = line.read(1)
  492.                         
  493.                         id = 'pml_toc-%s' % len(self.toc)
  494.                         value = self.code_value(line)
  495.                         if c == 'x':
  496.                             t = self.process_code(c, line)
  497.                         elif c == 'X':
  498.                             t = self.process_code('%s%s' % (c, level), line)
  499.                         
  500.                         if not value or value == '':
  501.                             text = t
  502.                         else:
  503.                             self.toc.add_item(os.path.basename(self.file_name), id, value)
  504.                             text = '%s<span id="%s"></span>' % (t, id)
  505.                     elif c == 'm':
  506.                         empty = False
  507.                         src = self.code_value(line)
  508.                         text = '<img src="images/%s" />' % src
  509.                     elif c == 'Q':
  510.                         empty = False
  511.                         id = self.code_value(line)
  512.                         text = '<span id="%s"></span>' % id
  513.                     elif c == 'p':
  514.                         empty = False
  515.                         text = '<br /><br style="page-break-after: always;" />'
  516.                     elif c == 'n':
  517.                         pass
  518.                     elif c == 'w':
  519.                         empty = False
  520.                         text = '<hr width="%s" />' % self.code_value(line)
  521.                     elif c == '-':
  522.                         empty = False
  523.                         text = '­'
  524.                     elif c == '\\':
  525.                         empty = False
  526.                         text = '\\'
  527.                     
  528.                 elif c != ' ':
  529.                     empty = False
  530.                 
  531.                 text = c
  532.                 parsed.append(text)
  533.                 c = line.read(1)
  534.             if not empty:
  535.                 text = self.end_line()
  536.                 parsed.append(text)
  537.                 output.append(u''.join(parsed))
  538.             
  539.             line.close()
  540.         
  541.         output = self.cleanup_html(u'\n'.join(output))
  542.         return output
  543.  
  544.     
  545.     def get_toc(self):
  546.         return self.toc
  547.  
  548.  
  549.  
  550. def pml_to_html(pml):
  551.     hizer = PML_HTMLizer()
  552.     return hizer.parse_pml(pml)
  553.  
  554.  
  555. def footnote_sidebar_to_html(pre_id, id, pml):
  556.     id = id.strip('\x01')
  557.     html = '<br /><br style="page-break-after: always;" /><div id="%s-%s"><p>%s</p><small><a href="#r%s-%s">return</a></small></div>' % (pre_id, id, pml_to_html(pml), pre_id, id)
  558.     return html
  559.  
  560.  
  561. def footnote_to_html(id, pml):
  562.     return footnote_sidebar_to_html('fn', id, pml)
  563.  
  564.  
  565. def sidebar_to_html(id, pml):
  566.     return footnote_sidebar_to_html('sb', id, pml)
  567.  
  568.