home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1066 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  16.4 KB  |  567 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.         return html
  175.  
  176.     
  177.     def cleanup_html_remove_redundant(self, html):
  178.         for key in self.STATES_TAGS.keys():
  179.             (open, close) = self.STATES_TAGS[key]
  180.             if key in self.STATES_VALUE_REQ:
  181.                 html = re.sub('(?u)%s\\s*%s' % (open % '.*?', close), '', html)
  182.                 continue
  183.             html = re.sub('(?u)%s\\s*%s' % (open, close), '', html)
  184.         
  185.         html = re.sub('<p>\\s*</p>', '', html)
  186.         return html
  187.  
  188.     
  189.     def start_line(self):
  190.         start = u''
  191.         div = []
  192.         span = []
  193.         other = []
  194.         for key, val in self.state.items():
  195.             if val[0]:
  196.                 if key in self.DIV_STATES:
  197.                     div.append((key, val[1]))
  198.                 elif key in self.SPAN_STATES:
  199.                     span.append((key, val[1]))
  200.                 else:
  201.                     other.append((key, val[1]))
  202.             key in self.DIV_STATES
  203.         
  204.         for key, val in other + div + span:
  205.             if key in self.STATES_VALUE_REQ:
  206.                 start += self.STATES_TAGS[key][0] % val
  207.                 continue
  208.             if key in self.STATES_VALUE_REQ_2:
  209.                 start += self.STATES_TAGS[key][0] % (val, val)
  210.                 continue
  211.             start += self.STATES_TAGS[key][0]
  212.         
  213.         return u'<p>%s' % start
  214.  
  215.     
  216.     def end_line(self):
  217.         end = u''
  218.         div = []
  219.         span = []
  220.         other = []
  221.         for key, val in self.state.items():
  222.             if val[0]:
  223.                 if key == 'T':
  224.                     self.state['T'][0] = False
  225.                 
  226.                 if key in self.DIV_STATES:
  227.                     div.append(key)
  228.                 elif key in self.SPAN_STATES:
  229.                     span.append(key)
  230.                 else:
  231.                     other.append(key)
  232.             key in self.DIV_STATES
  233.         
  234.         for key in span + div + other:
  235.             if key in self.STATES_CLOSE_VALUE_REQ:
  236.                 end += self.STATES_TAGS[key][1] % self.state[key][1]
  237.                 continue
  238.             end += self.STATES_TAGS[key][1]
  239.         
  240.         return u'%s</p>' % end
  241.  
  242.     
  243.     def process_code(self, code, stream, pre = ''):
  244.         text = u''
  245.         code = self.CODE_STATES.get(code, None)
  246.         if not code:
  247.             return text
  248.         if code in self.DIV_STATES:
  249.             if code == 'T' and self.state['T'][0]:
  250.                 self.code_value(stream)
  251.                 return text
  252.             text = self.process_code_div(code, stream)
  253.         elif code in self.SPAN_STATES:
  254.             text = self.process_code_span(code, stream)
  255.         elif code in self.BLOCK_STATES:
  256.             text = self.process_code_block(code, stream, pre)
  257.         else:
  258.             text = self.process_code_simple(code, stream)
  259.         self.state[code][0] = not self.state[code][0]
  260.         return text
  261.  
  262.     
  263.     def process_code_simple(self, code, stream):
  264.         text = u''
  265.         if self.state[code][0]:
  266.             if code in self.STATES_CLOSE_VALUE_REQ:
  267.                 text = self.STATES_TAGS[code][1] % self.state[code][1]
  268.             else:
  269.                 text = self.STATES_TAGS[code][1]
  270.         elif code in self.STATES_VALUE_REQ or code in self.STATES_VALUE_REQ_2:
  271.             val = self.code_value(stream)
  272.             if code in self.STATES_VALUE_REQ:
  273.                 text = self.STATES_TAGS[code][0] % val
  274.             else:
  275.                 text = self.STATES_TAGS[code][0] % (val, val)
  276.             self.state[code][1] = val
  277.         else:
  278.             text = self.STATES_TAGS[code][0]
  279.         return text
  280.  
  281.     
  282.     def process_code_div(self, code, stream):
  283.         text = u''
  284.         if self.state[code][0]:
  285.             for c in self.SPAN_STATES + self.DIV_STATES:
  286.                 if self.state[c][0]:
  287.                     if c in self.STATES_CLOSE_VALUE_REQ:
  288.                         text += self.STATES_TAGS[c][1] % self.state[c][1]
  289.                     else:
  290.                         text += self.STATES_TAGS[c][1]
  291.                 c in self.STATES_CLOSE_VALUE_REQ
  292.             
  293.             for c in self.DIV_STATES + self.SPAN_STATES:
  294.                 if code == c:
  295.                     continue
  296.                 
  297.                 if self.state[c][0]:
  298.                     if c in self.STATES_VALUE_REQ:
  299.                         text += self.STATES_TAGS[self.CODE_STATES[c]][0] % self.state[c][1]
  300.                     elif c in self.STATES_VALUE_REQ_2:
  301.                         text += self.STATES_TAGS[self.CODE_STATES[c]][0] % (self.state[c][1], self.state[c][1])
  302.                     else:
  303.                         text += self.STATES_TAGS[c][0]
  304.                 c in self.STATES_VALUE_REQ
  305.             
  306.         else:
  307.             for c in self.SPAN_STATES:
  308.                 if self.state[c][0]:
  309.                     if c in self.STATES_CLOSE_VALUE_REQ:
  310.                         text += self.STATES_TAGS[c][1] % self.state[c][1]
  311.                     else:
  312.                         text += self.STATES_TAGS[c][1]
  313.                 c in self.STATES_CLOSE_VALUE_REQ
  314.             
  315.             if code in self.STATES_VALUE_REQ or code in self.STATES_VALUE_REQ_2:
  316.                 val = self.code_value(stream)
  317.                 if code in self.STATES_VALUE_REQ:
  318.                     text += self.STATES_TAGS[code][0] % val
  319.                 else:
  320.                     text += self.STATES_TAGS[code][0] % (val, val)
  321.                 self.state[code][1] = val
  322.             else:
  323.                 text += self.STATES_TAGS[code][0]
  324.             for c in self.SPAN_STATES:
  325.                 if self.state[c][0]:
  326.                     if c in self.STATES_VALUE_REQ:
  327.                         text += self.STATES_TAGS[self.CODE_STATES[c]][0] % self.state[c][1]
  328.                     elif c in self.STATES_VALUE_REQ_2:
  329.                         text += self.STATES_TAGS[self.CODE_STATES[c]][0] % (self.state[c][1], self.state[c][1])
  330.                     else:
  331.                         text += self.STATES_TAGS[c][0]
  332.                 c in self.STATES_VALUE_REQ
  333.             
  334.         return text
  335.  
  336.     
  337.     def process_code_span(self, code, stream):
  338.         text = u''
  339.         if self.state[code][0]:
  340.             for c in self.SPAN_STATES:
  341.                 if self.state[c][0]:
  342.                     if c in self.STATES_CLOSE_VALUE_REQ:
  343.                         text += self.STATES_TAGS[c][1] % self.state[c][1]
  344.                     else:
  345.                         text += self.STATES_TAGS[c][1]
  346.                 c in self.STATES_CLOSE_VALUE_REQ
  347.             
  348.             for c in self.SPAN_STATES:
  349.                 if code == c:
  350.                     continue
  351.                 
  352.                 if self.state[c][0]:
  353.                     if c in self.STATES_VALUE_REQ:
  354.                         text += self.STATES_TAGS[code][0] % self.state[c][1]
  355.                     elif c in self.STATES_VALUE_REQ_2:
  356.                         text += self.STATES_TAGS[code][0] % (self.state[c][1], self.state[c][1])
  357.                     else:
  358.                         text += self.STATES_TAGS[c][0]
  359.                 c in self.STATES_VALUE_REQ
  360.             
  361.         elif code in self.STATES_VALUE_REQ or code in self.STATES_VALUE_REQ_2:
  362.             val = self.code_value(stream)
  363.             if code in self.STATES_VALUE_REQ:
  364.                 text += self.STATES_TAGS[code][0] % val
  365.             else:
  366.                 text += self.STATES_TAGS[code][0] % (val, val)
  367.             self.state[code][1] = val
  368.         else:
  369.             text += self.STATES_TAGS[code][0]
  370.         return text
  371.  
  372.     
  373.     def process_code_block(self, code, stream, pre = ''):
  374.         text = u''
  375.         for c in self.SPAN_STATES:
  376.             if self.state[c][0]:
  377.                 if c in self.STATES_CLOSE_VALUE_REQ:
  378.                     text += self.STATES_TAGS[c][1] % self.state[c][1]
  379.                 else:
  380.                     text += self.STATES_TAGS[c][1]
  381.             c in self.STATES_CLOSE_VALUE_REQ
  382.         
  383.         if self.state[code][0]:
  384.             if code in self.STATES_CLOSE_VALUE_REQ:
  385.                 text += self.STATES_TAGS[code][1] % self.state[code][1]
  386.             else:
  387.                 text += self.STATES_TAGS[code][1]
  388.         elif code in self.STATES_VALUE_REQ or code in self.STATES_VALUE_REQ_2:
  389.             val = self.code_value(stream)
  390.             if code in self.LINK_STATES:
  391.                 val = val.lstrip('#')
  392.             
  393.             if pre:
  394.                 val = '%s-%s' % (pre, val)
  395.             
  396.             if code in self.STATES_VALUE_REQ:
  397.                 text += self.STATES_TAGS[code][0] % val
  398.             else:
  399.                 text += self.STATES_TAGS[code][0] % (val, val)
  400.             self.state[code][1] = val
  401.         else:
  402.             text += self.STATES_TAGS[code][0]
  403.         for c in self.SPAN_STATES:
  404.             if self.state[c][0]:
  405.                 if c in self.STATES_VALUE_REQ:
  406.                     text += self.STATES_TAGS[code][0] % self.state[c][1]
  407.                 elif c in self.STATES_VALUE_REQ_2:
  408.                     text += self.STATES_TAGS[code][0] % (self.state[c][1], self.state[c][1])
  409.                 else:
  410.                     text += self.STATES_TAGS[c][0]
  411.             c in self.STATES_VALUE_REQ
  412.         
  413.         return text
  414.  
  415.     
  416.     def code_value(self, stream):
  417.         value = u''
  418.         state = 0
  419.         loc = stream.tell()
  420.         c = stream.read(1)
  421.         while c != '':
  422.             if state == 0:
  423.                 if c == '=':
  424.                     state = 1
  425.                 elif c != ' ':
  426.                     break
  427.                 
  428.             elif state == 1:
  429.                 if c == '"':
  430.                     state = 2
  431.                 elif c != ' ':
  432.                     break
  433.                 
  434.             elif state == 2:
  435.                 if c == '"':
  436.                     state = 3
  437.                     break
  438.                 else:
  439.                     value += c
  440.             
  441.             c = stream.read(1)
  442.         if state != 3:
  443.             stream.seek(loc)
  444.             value = u''
  445.         
  446.         return value.strip()
  447.  
  448.     
  449.     def parse_pml(self, pml, file_name = ''):
  450.         pml = self.prepare_pml(pml)
  451.         output = []
  452.         self.state = { }
  453.         self.toc = TOC()
  454.         self.file_name = file_name
  455.         for s in self.STATES:
  456.             self.state[s] = [
  457.                 False,
  458.                 '']
  459.         
  460.         for line in pml.splitlines():
  461.             if not line:
  462.                 continue
  463.             
  464.             parsed = []
  465.             empty = True
  466.             line = StringIO.StringIO(line)
  467.             parsed.append(self.start_line())
  468.             c = line.read(1)
  469.             while c != '':
  470.                 text = u''
  471.                 if c == '\\':
  472.                     c = line.read(1)
  473.                     if c in 'qcrtTiIuobBlk':
  474.                         text = self.process_code(c, line)
  475.                     elif c in 'FS':
  476.                         l = line.read(1)
  477.                         if '%s%s' % (c, l) == 'Fn':
  478.                             text = self.process_code('Fn', line, 'fn')
  479.                         elif '%s%s' % (c, l) == 'FN':
  480.                             text = self.process_code('FN', line)
  481.                         elif '%s%s' % (c, l) == 'SB':
  482.                             text = self.process_code('SB', line)
  483.                         elif '%s%s' % (c, l) == 'Sd':
  484.                             text = self.process_code('Sd', line, 'sb')
  485.                         
  486.                     elif c in 'xXC':
  487.                         empty = False
  488.                         t = ''
  489.                         if c in 'XC':
  490.                             level = line.read(1)
  491.                         
  492.                         id = 'pml_toc-%s' % len(self.toc)
  493.                         value = self.code_value(line)
  494.                         if c == 'x':
  495.                             t = self.process_code(c, line)
  496.                         elif c == 'X':
  497.                             t = self.process_code('%s%s' % (c, level), line)
  498.                         
  499.                         if not value or value == '':
  500.                             text = t
  501.                         else:
  502.                             self.toc.add_item(os.path.basename(self.file_name), id, value)
  503.                             text = '<span id="%s"></span>%s' % (id, t)
  504.                     elif c == 'm':
  505.                         empty = False
  506.                         src = self.code_value(line)
  507.                         text = '<img src="images/%s" />' % src
  508.                     elif c == 'Q':
  509.                         empty = False
  510.                         id = self.code_value(line)
  511.                         text = '<span id="%s"></span>' % id
  512.                     elif c == 'p':
  513.                         empty = False
  514.                         text = '<br /><br style="page-break-after: always;" />'
  515.                     elif c == 'n':
  516.                         pass
  517.                     elif c == 'w':
  518.                         empty = False
  519.                         text = '<hr width="%s" />' % self.code_value(line)
  520.                     elif c == '-':
  521.                         empty = False
  522.                         text = '­'
  523.                     elif c == '\\':
  524.                         empty = False
  525.                         text = '\\'
  526.                     
  527.                 elif c != ' ':
  528.                     empty = False
  529.                 
  530.                 text = c
  531.                 parsed.append(text)
  532.                 c = line.read(1)
  533.             if not empty:
  534.                 text = self.end_line()
  535.                 parsed.append(text)
  536.                 output.append(u''.join(parsed))
  537.             
  538.             line.close()
  539.         
  540.         output = self.cleanup_html(u'\n'.join(output))
  541.         return output
  542.  
  543.     
  544.     def get_toc(self):
  545.         return self.toc
  546.  
  547.  
  548.  
  549. def pml_to_html(pml):
  550.     hizer = PML_HTMLizer()
  551.     return hizer.parse_pml(pml)
  552.  
  553.  
  554. def footnote_sidebar_to_html(pre_id, id, pml):
  555.     id = id.strip('\x01')
  556.     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)
  557.     return html
  558.  
  559.  
  560. def footnote_to_html(id, pml):
  561.     return footnote_sidebar_to_html('fn', id, pml)
  562.  
  563.  
  564. def sidebar_to_html(id, pml):
  565.     return footnote_sidebar_to_html('sb', id, pml)
  566.  
  567.