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

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
  6. __docformat__ = 'restructuredtext en'
  7. import functools
  8. import re
  9. from calibre import entity_to_unicode
  10. XMLDECL_RE = re.compile('^\\s*<[?]xml.*?[?]>')
  11. SVG_NS = 'http://www.w3.org/2000/svg'
  12. XLINK_NS = 'http://www.w3.org/1999/xlink'
  13. convert_entities = functools.partial(entity_to_unicode, result_exceptions = {
  14.     u'<': '<',
  15.     u'>': '>',
  16.     u"'": ''',
  17.     u'"': '"',
  18.     u'&': '&' })
  19. _span_pat = re.compile('<span.*?</span>', re.DOTALL | re.IGNORECASE)
  20. LIGATURES = {
  21.     u'∩¼Ç': u'ff',
  22.     u'∩¼ü': u'fi',
  23.     u'∩¼é': u'fl',
  24.     u'∩¼â': u'ffi',
  25.     u'∩¼ä': u'ffl',
  26.     u'∩¼à': u'ft',
  27.     u'∩¼å': u'st' }
  28. _ligpat = re.compile(u'|'.join(LIGATURES))
  29.  
  30. def sanitize_head(match):
  31.     x = match.group(1)
  32.     x = _span_pat.sub('', x)
  33.     return '<head>\n%s\n</head>' % x
  34.  
  35.  
  36. def chap_head(match):
  37.     chap = match.group('chap')
  38.     title = match.group('title')
  39.     if not title:
  40.         return '<h1>' + chap + '</h1><br/>\n'
  41.     return '<h1>' + chap + '<br/>\n' + title + '</h1><br/>\n'
  42.  
  43.  
  44. def wrap_lines(match):
  45.     ital = match.group('ital')
  46.     if not ital:
  47.         return ' '
  48.     return ital + ' '
  49.  
  50.  
  51. def line_length(raw, percent):
  52.     raw = raw.replace(' ', ' ')
  53.     linere = re.compile('(?<=<br>).*?(?=<br>)', re.DOTALL)
  54.     lines = linere.findall(raw)
  55.     lengths = []
  56.     for line in lines:
  57.         if len(line) > 0:
  58.             lengths.append(len(line))
  59.             continue
  60.     
  61.     if not lengths:
  62.         return 0
  63.     lengths = list(set(lengths))
  64.     total = sum(lengths)
  65.     avg = total / len(lengths)
  66.     max_line = avg * 2
  67.     lengths = sorted(lengths)
  68.     for i in range(len(lengths) - 1, -1, -1):
  69.         if lengths[i] > max_line:
  70.             del lengths[i]
  71.             continue
  72.         lengths
  73.     
  74.     if percent > 1:
  75.         percent = 1
  76.     
  77.     if percent < 0:
  78.         percent = 0
  79.     
  80.     index = int(len(lengths) * percent) - 1
  81.     return lengths[index]
  82.  
  83.  
  84. class CSSPreProcessor(object):
  85.     PAGE_PAT = re.compile('@page[^{]*?{[^}]*?}')
  86.     
  87.     def __call__(self, data, add_namespace = False):
  88.         XHTML_CSS_NAMESPACE = XHTML_CSS_NAMESPACE
  89.         import calibre.ebooks.oeb.base
  90.         data = self.PAGE_PAT.sub('', data)
  91.         if not add_namespace:
  92.             return data
  93.         ans = []
  94.         namespaced = False
  95.         for line in data.splitlines():
  96.             ll = line.lstrip()
  97.             if not namespaced and ll.startswith('@import') or ll.startswith('@charset'):
  98.                 ans.append(XHTML_CSS_NAMESPACE.strip())
  99.                 namespaced = True
  100.             
  101.             ans.append(line)
  102.         
  103.         return u'\n'.join(ans)
  104.  
  105.  
  106.  
  107. class HTMLPreProcessor(object):
  108.     PREPROCESS = [
  109.         (re.compile('<head[^>]*>\\n*(.*?)\\n*</head>', re.IGNORECASE | re.DOTALL), sanitize_head),
  110.         (re.compile('&(\\S+?);'), convert_entities),
  111.         (re.compile('</{0,1}!\\[(end){0,1}if\\]{0,1}>', re.IGNORECASE), (lambda match: ''))]
  112.     PDFTOHTML = [
  113.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*o', re.UNICODE), (lambda match: u'├╢')),
  114.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*O', re.UNICODE), (lambda match: u'├û')),
  115.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*u', re.UNICODE), (lambda match: u'├╝')),
  116.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*U', re.UNICODE), (lambda match: u'├£')),
  117.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*e', re.UNICODE), (lambda match: u'├½')),
  118.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*E', re.UNICODE), (lambda match: u'├ï')),
  119.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*i', re.UNICODE), (lambda match: u'├»')),
  120.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*I', re.UNICODE), (lambda match: u'├Å')),
  121.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*a', re.UNICODE), (lambda match: u'├ñ')),
  122.         (re.compile(u'┬¿\\s*(<br.*?>)*\\s*A', re.UNICODE), (lambda match: u'├ä')),
  123.         (re.compile(u'`\\s*(<br.*?>)*\\s*o', re.UNICODE), (lambda match: u'├▓')),
  124.         (re.compile(u'`\\s*(<br.*?>)*\\s*O', re.UNICODE), (lambda match: u'├Æ')),
  125.         (re.compile(u'`\\s*(<br.*?>)*\\s*u', re.UNICODE), (lambda match: u'├╣')),
  126.         (re.compile(u'`\\s*(<br.*?>)*\\s*U', re.UNICODE), (lambda match: u'├Ö')),
  127.         (re.compile(u'`\\s*(<br.*?>)*\\s*e', re.UNICODE), (lambda match: u'├¿')),
  128.         (re.compile(u'`\\s*(<br.*?>)*\\s*E', re.UNICODE), (lambda match: u'├ê')),
  129.         (re.compile(u'`\\s*(<br.*?>)*\\s*i', re.UNICODE), (lambda match: u'├¼')),
  130.         (re.compile(u'`\\s*(<br.*?>)*\\s*I', re.UNICODE), (lambda match: u'├î')),
  131.         (re.compile(u'`\\s*(<br.*?>)*\\s*a', re.UNICODE), (lambda match: u'├á')),
  132.         (re.compile(u'`\\s*(<br.*?>)*\\s*A', re.UNICODE), (lambda match: u'├Ç')),
  133.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*o', re.UNICODE), (lambda match: u'├│')),
  134.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*O', re.UNICODE), (lambda match: u'├ô')),
  135.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*u', re.UNICODE), (lambda match: u'├║')),
  136.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*U', re.UNICODE), (lambda match: u'├Ü')),
  137.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*e', re.UNICODE), (lambda match: u'├⌐')),
  138.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*E', re.UNICODE), (lambda match: u'├ë')),
  139.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*i', re.UNICODE), (lambda match: u'├¡')),
  140.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*I', re.UNICODE), (lambda match: u'├ì')),
  141.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*a', re.UNICODE), (lambda match: u'├í')),
  142.         (re.compile(u'┬┤\\s*(<br.*?>)*\\s*A', re.UNICODE), (lambda match: u'├ü')),
  143.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*o', re.UNICODE), (lambda match: u'├┤')),
  144.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*O', re.UNICODE), (lambda match: u'├ö')),
  145.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*u', re.UNICODE), (lambda match: u'├╗')),
  146.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*U', re.UNICODE), (lambda match: u'├¢')),
  147.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*e', re.UNICODE), (lambda match: u'├¬')),
  148.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*E', re.UNICODE), (lambda match: u'├è')),
  149.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*i', re.UNICODE), (lambda match: u'├«')),
  150.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*I', re.UNICODE), (lambda match: u'├Ä')),
  151.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*a', re.UNICODE), (lambda match: u'├ó')),
  152.         (re.compile(u'╦å\\s*(<br.*?>)*\\s*A', re.UNICODE), (lambda match: u'├é')),
  153.         (re.compile(u'┬╕\\s*(<br.*?>)*\\s*c', re.UNICODE), (lambda match: u'├º')),
  154.         (re.compile(u'┬╕\\s*(<br.*?>)*\\s*C', re.UNICODE), (lambda match: u'├ç')),
  155.         (re.compile('<a name=\\d+></a>', re.IGNORECASE), (lambda match: '')),
  156.         (re.compile('<hr.*?>', re.IGNORECASE), (lambda match: '<br />')),
  157.         (re.compile('<br.*?>\\s*<br.*?>', re.IGNORECASE), (lambda match: '<p>')),
  158.         (re.compile('-<br.*?>\\n\\r?'), (lambda match: '')),
  159.         (re.compile('<BODY[^<>]+>'), (lambda match: '<BODY>')),
  160.         (re.compile(u'┬á'), (lambda match: ' ')),
  161.         (re.compile('(?=<(/?br|p))(<(/?br|p)[^>]*)?>\\s*(?P<chap>(<i><b>|<i>|<b>)?(Chapter|Epilogue|Prologue|Book|Part)\\s*([\\d\\w-]+)?(</i></b>|</i>|</b>)?)(</?p[^>]*>|<br[^>]*>)\\n?((?=(<i>)?\\s*\\w+(\\s+\\w+)?(</i>)?(<br[^>]*>|</?p[^>]*>))((?P<title>(<i>)?\\s*\\w+(\\s+\\w+)?(</i>)?)(<br[^>]*>|</?p[^>]*>)))?', re.IGNORECASE), chap_head),
  162.         (re.compile('(?=<(/?br|p))(<(/?br|p)[^>]*)?>\\s*(?P<chap>([A-Z \\\'"!]{5,})\\s*(\\d+|\\w+)?)(</?p[^>]*>|<br[^>]*>)\\n?((?=(<i>)?\\s*\\w+(\\s+\\w+)?(</i>)?(<br[^>]*>|</?p[^>]*>))((?P<title>.*)(<br[^>]*>|</?p[^>]*>)))?'), chap_head),
  163.         (re.compile('<br.*?>'), (lambda match: '<p>')),
  164.         (re.compile(u'(?<=[\\.,;\\?!ΓÇ¥"\'])[\\s^ ]*(?=<)'), (lambda match: ' ')),
  165.         (re.compile(u'(?<=[^\\s][-ΓÇô])[\\s]*(</p>)*[\\s]*(<p>)*\\s*(?=[^\\s])'), (lambda match: '')),
  166.         (re.compile(u'(?<!ΓÇ£)<i>'), (lambda match: ' <i>')),
  167.         (re.compile('</i>(?=\\w)'), (lambda match: '</i> '))]
  168.     BOOK_DESIGNER = [
  169.         (re.compile('<hr>', re.IGNORECASE), (lambda match: '<span style="page-break-after:always"> </span>')),
  170.         (re.compile('<h2[^><]*?id=BookTitle[^><]*?(align=)*(?(1)(\\w+))*[^><]*?>[^><]*?</h2>', re.IGNORECASE), (lambda match: None % ('<h1 id="BookTitle" align="%s">%s</h1>' if match.group(2) else 'center', match.group(3)))),
  171.         (re.compile('<h2[^><]*?id=BookAuthor[^><]*?(align=)*(?(1)(\\w+))*[^><]*?>[^><]*?</h2>', re.IGNORECASE), (lambda match: None % ('<h2 id="BookAuthor" align="%s">%s</h2>' if match.group(2) else 'center', match.group(3)))),
  172.         (re.compile('<span[^><]*?id=title[^><]*?>(.*?)</span>', re.IGNORECASE | re.DOTALL), (lambda match: '<h2 class="title">%s</h2>' % (match.group(1),))),
  173.         (re.compile('<span[^><]*?id=subtitle[^><]*?>(.*?)</span>', re.IGNORECASE | re.DOTALL), (lambda match: '<h3 class="subtitle">%s</h3>' % (match.group(1),)))]
  174.     
  175.     def __init__(self, input_plugin_preprocess, plugin_preprocess, extra_opts = None):
  176.         self.input_plugin_preprocess = input_plugin_preprocess
  177.         self.plugin_preprocess = plugin_preprocess
  178.         self.extra_opts = extra_opts
  179.  
  180.     
  181.     def is_baen(self, src):
  182.         return re.compile('<meta\\s+name="Publisher"\\s+content=".*?Baen.*?"', re.IGNORECASE).search(src) is not None
  183.  
  184.     
  185.     def is_book_designer(self, raw):
  186.         return re.search('<H2[^><]*id=BookTitle', raw) is not None
  187.  
  188.     
  189.     def is_pdftohtml(self, src):
  190.         return "<!-- created by calibre's pdftohtml -->" in src[:1000]
  191.  
  192.     
  193.     def __call__(self, html, remove_special_chars = None):
  194.         if remove_special_chars is not None:
  195.             html = remove_special_chars.sub('', html)
  196.         
  197.         html = html.replace('\x00', '')
  198.         if self.is_baen(html):
  199.             rules = []
  200.         elif self.is_book_designer(html):
  201.             rules = self.BOOK_DESIGNER
  202.         elif self.is_pdftohtml(html):
  203.             rules = self.PDFTOHTML
  204.         else:
  205.             rules = []
  206.         if not self.extra_opts.keep_ligatures:
  207.             html = _ligpat.sub((lambda m: LIGATURES[m.group()]), html)
  208.         
  209.         end_rules = []
  210.         if getattr(self.extra_opts, 'remove_header', None):
  211.             
  212.             try:
  213.                 rules.insert(0, (re.compile(self.extra_opts.header_regex), (lambda match: '')))
  214.             import traceback
  215.             print 'Failed to parse remove_header regexp'
  216.             traceback.print_exc()
  217.  
  218.         
  219.         if getattr(self.extra_opts, 'remove_footer', None):
  220.             
  221.             try:
  222.                 rules.insert(0, (re.compile(self.extra_opts.footer_regex), (lambda match: '')))
  223.             import traceback
  224.             print 'Failed to parse remove_footer regexp'
  225.             traceback.print_exc()
  226.  
  227.         
  228.         if getattr(self.extra_opts, 'unwrap_factor', 0) > 0.01:
  229.             length = line_length(html, getattr(self.extra_opts, 'unwrap_factor'))
  230.             if length:
  231.                 end_rules.append((re.compile('(?<=.{%i}[a-z\\.,;:)\\-IA])\\s*(?P<ital></(i|b|u)>)?\\s*(<p.*?>)\\s*(?=(<(i|b|u)>)?\\s*[\\w\\d(])' % length, re.UNICODE), wrap_lines))
  232.             
  233.         
  234.         for rule in self.PREPROCESS + rules + end_rules:
  235.             html = rule[0].sub(rule[1], html)
  236.         
  237.         if 'svg:' in html and SVG_NS not in html:
  238.             html = html.replace('<html', '<html xmlns:svg="%s"' % SVG_NS, 1)
  239.         
  240.         if 'xlink:' in html and XLINK_NS not in html:
  241.             html = html.replace('<html', '<html xmlns:xlink="%s"' % XLINK_NS, 1)
  242.         
  243.         html = XMLDECL_RE.sub('', html)
  244.         if getattr(self.extra_opts, 'asciiize', False):
  245.             Unidecoder = Unidecoder
  246.             import calibre.ebooks.unidecode.unidecoder
  247.             unidecoder = Unidecoder()
  248.             html = unidecoder.decode(html)
  249.         
  250.         if self.plugin_preprocess:
  251.             html = self.input_plugin_preprocess(html)
  252.         
  253.         return html
  254.  
  255.  
  256.