Fix #2350 (conversion of a mobipocket file (huffdic compressed) fail)

This commit is contained in:
Kovid Goyal 2009-04-26 15:25:25 -07:00
parent 54dd263be1
commit 8e68f9d4dd
2 changed files with 35 additions and 32 deletions

View File

@ -382,6 +382,7 @@ class MobiReader(object):
} }
mobi_version = self.book_header.mobi_version mobi_version = self.book_header.mobi_version
for tag in root.iter(etree.Element): for tag in root.iter(etree.Element):
tag.attrib.pop('xmlns', '')
if tag.tag in ('country-region', 'place', 'placetype', 'placename', if tag.tag in ('country-region', 'place', 'placetype', 'placename',
'state', 'city', 'street', 'address', 'content'): 'state', 'city', 'street', 'address', 'content'):
tag.tag = 'div' if tag.tag == 'content' else 'span' tag.tag = 'div' if tag.tag == 'content' else 'span'

View File

@ -7,22 +7,22 @@ import sys, re, os
class TerminalController: class TerminalController:
""" """
A class that can be used to portably generate formatted output to A class that can be used to portably generate formatted output to
a terminal. a terminal.
`TerminalController` defines a set of instance variables whose `TerminalController` defines a set of instance variables whose
values are initialized to the control sequence necessary to values are initialized to the control sequence necessary to
perform a given action. These can be simply included in normal perform a given action. These can be simply included in normal
output to the terminal: output to the terminal:
>>> term = TerminalController() >>> term = TerminalController()
>>> print 'This is '+term.GREEN+'green'+term.NORMAL >>> print 'This is '+term.GREEN+'green'+term.NORMAL
Alternatively, the `render()` method can used, which replaces Alternatively, the `render()` method can used, which replaces
'${action}' with the string required to perform 'action': '${action}' with the string required to perform 'action':
>>> term = TerminalController() >>> term = TerminalController()
>>> print term.render('This is ${GREEN}green${NORMAL}') >>> print term.render('This is ${GREEN}green${NORMAL}')
If the terminal doesn't support a given action, then the value of If the terminal doesn't support a given action, then the value of
the corresponding instance variable will be set to ''. As a the corresponding instance variable will be set to ''. As a
result, the above code will still work on terminals that do not result, the above code will still work on terminals that do not
@ -30,11 +30,11 @@ class TerminalController:
Also, this means that you can test whether the terminal supports a Also, this means that you can test whether the terminal supports a
given action by simply testing the truth value of the given action by simply testing the truth value of the
corresponding instance variable: corresponding instance variable:
>>> term = TerminalController() >>> term = TerminalController()
>>> if term.CLEAR_SCREEN: >>> if term.CLEAR_SCREEN:
... print 'This terminal supports clearning the screen.' ... print 'This terminal supports clearning the screen.'
Finally, if the width and height of the terminal are known, then Finally, if the width and height of the terminal are known, then
they will be stored in the `COLS` and `LINES` attributes. they will be stored in the `COLS` and `LINES` attributes.
""" """
@ -44,35 +44,35 @@ class TerminalController:
DOWN = '' #: Move the cursor down one line DOWN = '' #: Move the cursor down one line
LEFT = '' #: Move the cursor left one char LEFT = '' #: Move the cursor left one char
RIGHT = '' #: Move the cursor right one char RIGHT = '' #: Move the cursor right one char
# Deletion: # Deletion:
CLEAR_SCREEN = '' #: Clear the screen and move to home position CLEAR_SCREEN = '' #: Clear the screen and move to home position
CLEAR_EOL = '' #: Clear to the end of the line. CLEAR_EOL = '' #: Clear to the end of the line.
CLEAR_BOL = '' #: Clear to the beginning of the line. CLEAR_BOL = '' #: Clear to the beginning of the line.
CLEAR_EOS = '' #: Clear to the end of the screen CLEAR_EOS = '' #: Clear to the end of the screen
# Output modes: # Output modes:
BOLD = '' #: Turn on bold mode BOLD = '' #: Turn on bold mode
BLINK = '' #: Turn on blink mode BLINK = '' #: Turn on blink mode
DIM = '' #: Turn on half-bright mode DIM = '' #: Turn on half-bright mode
REVERSE = '' #: Turn on reverse-video mode REVERSE = '' #: Turn on reverse-video mode
NORMAL = '' #: Turn off all modes NORMAL = '' #: Turn off all modes
# Cursor display: # Cursor display:
HIDE_CURSOR = '' #: Make the cursor invisible HIDE_CURSOR = '' #: Make the cursor invisible
SHOW_CURSOR = '' #: Make the cursor visible SHOW_CURSOR = '' #: Make the cursor visible
# Terminal size: # Terminal size:
COLS = None #: Width of the terminal (None for unknown) COLS = None #: Width of the terminal (None for unknown)
LINES = None #: Height of the terminal (None for unknown) LINES = None #: Height of the terminal (None for unknown)
# Foreground colors: # Foreground colors:
BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = '' BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
# Background colors: # Background colors:
BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = '' BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = '' BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
_STRING_CAPABILITIES = """ _STRING_CAPABILITIES = """
BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1 BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
@ -80,7 +80,7 @@ class TerminalController:
HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split() HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
_COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split() _COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
_ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split() _ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
def __init__(self, term_stream=sys.stdout): def __init__(self, term_stream=sys.stdout):
""" """
Create a `TerminalController` and initialize its attributes Create a `TerminalController` and initialize its attributes
@ -92,24 +92,24 @@ class TerminalController:
# Curses isn't available on all platforms # Curses isn't available on all platforms
try: import curses try: import curses
except: return except: return
# If the stream isn't a tty, then assume it has no capabilities. # If the stream isn't a tty, then assume it has no capabilities.
if os.environ.get('CALIBRE_WORKER', None) is not None or not hasattr(term_stream, 'isatty') or not term_stream.isatty(): return if os.environ.get('CALIBRE_WORKER', None) is not None or not hasattr(term_stream, 'isatty') or not term_stream.isatty(): return
# Check the terminal type. If we fail, then assume that the # Check the terminal type. If we fail, then assume that the
# terminal has no capabilities. # terminal has no capabilities.
try: curses.setupterm() try: curses.setupterm()
except: return except: return
# Look up numeric capabilities. # Look up numeric capabilities.
self.COLS = curses.tigetnum('cols') self.COLS = curses.tigetnum('cols')
self.LINES = curses.tigetnum('lines') self.LINES = curses.tigetnum('lines')
# Look up string capabilities. # Look up string capabilities.
for capability in self._STRING_CAPABILITIES: for capability in self._STRING_CAPABILITIES:
(attrib, cap_name) = capability.split('=') (attrib, cap_name) = capability.split('=')
setattr(self, attrib, self._tigetstr(cap_name) or '') setattr(self, attrib, self._tigetstr(cap_name) or '')
# Colors # Colors
set_fg = self._tigetstr('setf') set_fg = self._tigetstr('setf')
if set_fg: if set_fg:
@ -127,7 +127,7 @@ class TerminalController:
if set_bg_ansi: if set_bg_ansi:
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS): for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '') setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
def _tigetstr(self, cap_name): def _tigetstr(self, cap_name):
# String capabilities can include "delays" of the form "$<2>". # String capabilities can include "delays" of the form "$<2>".
# For any modern terminal, we should be able to just ignore # For any modern terminal, we should be able to just ignore
@ -135,7 +135,7 @@ class TerminalController:
import curses import curses
cap = curses.tigetstr(cap_name) or '' cap = curses.tigetstr(cap_name) or ''
return re.sub(r'\$<\d+>[/*]?', '', cap) return re.sub(r'\$<\d+>[/*]?', '', cap)
def render(self, template): def render(self, template):
""" """
Replace each $-substitutions in the given template string with Replace each $-substitutions in the given template string with
@ -143,7 +143,7 @@ class TerminalController:
'' (if it's not). '' (if it's not).
""" """
return re.sub(r'\$\$|\${\w+}', self._render_sub, template) return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
def _render_sub(self, match): def _render_sub(self, match):
s = match.group() s = match.group()
if s == '$$': return s if s == '$$': return s
@ -156,20 +156,20 @@ class TerminalController:
class ProgressBar: class ProgressBar:
""" """
A 3-line progress bar, which looks like:: A 3-line progress bar, which looks like::
Header Header
20% [===========----------------------------------] 20% [===========----------------------------------]
progress message progress message
The progress bar is colored, if the terminal supports color The progress bar is colored, if the terminal supports color
output; and adjusts to the width of the terminal. output; and adjusts to the width of the terminal.
If the terminal doesn't have the required capabilities, it uses a If the terminal doesn't have the required capabilities, it uses a
simple progress bar. simple progress bar.
""" """
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n' BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n' HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
def __init__(self, term, header, no_progress_bar = False): def __init__(self, term, header, no_progress_bar = False):
self.term, self.no_progress_bar = term, no_progress_bar self.term, self.no_progress_bar = term, no_progress_bar
self.fancy = self.term.CLEAR_EOL and self.term.UP and self.term.BOL self.fancy = self.term.CLEAR_EOL and self.term.UP and self.term.BOL
@ -177,12 +177,14 @@ class ProgressBar:
self.width = self.term.COLS or 75 self.width = self.term.COLS or 75
self.bar = term.render(self.BAR) self.bar = term.render(self.BAR)
self.header = self.term.render(self.HEADER % header.center(self.width)) self.header = self.term.render(self.HEADER % header.center(self.width))
if isinstance(self.header, unicode):
self.header = self.header.encode('utf-8')
self.cleared = 1 #: true if we haven't drawn the bar yet. self.cleared = 1 #: true if we haven't drawn the bar yet.
def update(self, percent, message=''): def update(self, percent, message=''):
if isinstance(message, unicode): if isinstance(message, unicode):
message = message.encode('utf-8', 'replace') message = message.encode('utf-8', 'replace')
if self.no_progress_bar: if self.no_progress_bar:
if message: if message:
print message print message
@ -203,8 +205,8 @@ class ProgressBar:
else: else:
print '%d%%'%(percent*100), message print '%d%%'%(percent*100), message
sys.stdout.flush() sys.stdout.flush()
def clear(self): def clear(self):
if self.fancy and not self.cleared: if self.fancy and not self.cleared:
sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +