Partial implementation of lrs2lrf from Roger Critchlow

This commit is contained in:
Kovid Goyal 2008-01-11 18:39:03 +00:00
parent d44fed3ef2
commit d7fa576f6f
5 changed files with 1050 additions and 24 deletions

View File

@ -37,6 +37,7 @@ entry_points = {
'pdf2lrf = libprs500.ebooks.lrf.pdf.convert_from:main', 'pdf2lrf = libprs500.ebooks.lrf.pdf.convert_from:main',
'any2lrf = libprs500.ebooks.lrf.any.convert_from:main', 'any2lrf = libprs500.ebooks.lrf.any.convert_from:main',
'lrf2lrs = libprs500.ebooks.lrf.parser:main', 'lrf2lrs = libprs500.ebooks.lrf.parser:main',
'lrs2lrf = libprs500.ebooks.lrf.lrs.convert_from:main',
'isbndb = libprs500.ebooks.metadata.isbndb:main', 'isbndb = libprs500.ebooks.metadata.isbndb:main',
'librarything = libprs500.ebooks.metadata.library_thing:main', 'librarything = libprs500.ebooks.metadata.library_thing:main',
'lrf2html = libprs500.ebooks.lrf.html.convert_to:main', 'lrf2html = libprs500.ebooks.lrf.html.convert_to:main',

View File

@ -0,0 +1,953 @@
## Copyright (C) 2008 Roger Critchlow
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# major mismatch in Button/ButtonBlock/JumpButton
# major mismatch in providing referenced object instead of object reference
#
import sys, os
try:
from elementtree.ElementTree import ElementTree
except ImportError:
from xml.etree.ElementTree import ElementTree
from libprs500.ebooks.lrf.pylrs.pylrs import \
Book, StyleDefault, BookSetting, \
ImageBlock, Header, Footer, PutObj, \
Paragraph, CR, Italic, Bold, ImageStream, \
CharButton, Button, PushButton, JumpTo, \
Plot, Image, RuledLine, Canvas, DropCaps, \
Sup, Sub, Span, Text, \
LrsError, Space, Box, ButtonBlock, NoBR
from libprs500 import __appname__, __version__
class LrsParser(object):
filterAttrib = ['objid', 'refobj', 'objlabel', 'pagestyle', 'blockstyle', 'textstyle', 'stylelabel',
'evenheaderid', 'oddheaderid', 'evenfooterid', 'oddfooterid']
def __init__(self, file):
self.file = file
self.book = Book()
self.objects = dict()
self.dobjects = dict()
self.tocs = list()
self.charbuttons = list()
self.jumptos = list()
self.pagestyles = list()
self.blockstyles = list()
self.textstyles = list()
self.footers = list()
self.headers = list()
self.putobjs = list()
self.root = ElementTree(file=file)
#
# find an element by objid
#
def get_element_by_objid(self, objid):
if objid not in self.objects:
for element in self.root.getiterator():
if 'objid' in element.attrib:
id = element.attrib['objid']
if id not in self.objects:
self.objects[id] = element
elif self.objects[id] != element:
raise LrsError, "multiple objects with same objid=%d, %s and %s"%(id, element.tag, self.objects[id].tag)
if id == objid:
break
if objid in self.objects:
return self.objects[objid]
return None
#
# compare two attrib dictionaries for equivalence
#
def equal_attrib(self, e1, e2):
#print "comparing %s to %s in equal_attrib"%(e1.tag,e2.tag)
a1 = e1.attrib
a2 = e2.attrib
ignore = LrsParser.filterAttrib
for name in a1.keys():
if name in ignore:
continue
if name not in a2:
#print "compare: %s in e1 not in e2"%name
return False
if a1[name] != a2[name]:
#print "compare: %s e1=%s != e2=%s"%(name, a1[name], a2[name])
return False
for name in a2.keys():
if name in ignore:
continue
if name not in a1:
#print "compare: %s in e1 not in e2"%name
return False
if a1[name] != a2[name]:
#print "compare: %s e1=%s != e2=%s"%(name, a1[name], a2[name])
return False
return True
#
# process an attrib dictionary for passing into a pylrs create
#
def process_attrib(self, element):
attrib = element.attrib.copy()
for name in LrsParser.filterAttrib:
if name in attrib:
id = attrib[name]
if name == 'objid':
if id not in self.objects:
self.objects[id] = element
elif self.objects[id] != element:
raise LrsError, "multiple objects with same objid=%s, %s and %s"%(id, element.tag, self.objects[id].tag)
del attrib[name]
return attrib
#
# get and parse a style element
#
def fetch_style(self, element, stylename):
"""get the style element referenced by stylename in element.attrib"""
if stylename not in element.attrib:
return None
id = element.attrib[stylename]
if id in self.dobjects:
return self.dobjects[id]
style = self.get_element_by_objid(id)
if style == None:
raise LrsError, "no %s style element found for objid=%s"%(stylename, id)
#print "found style type %s with objid = %s after getting %s"%(style.tag, style.attrib['objid'], id)
newstyle = None
#
# yuck - headers and footers really mess this up
#
if stylename == 'pagestyle':
for e in self.pagestyles:
if self.equal_attrib(e, style):
#print "making pagestyle %s alias to %s"%(id, e.attrib['objid'])
newstyle = self.dobjects[e.attrib['objid']]
break
if newstyle == None:
#print "making pagestyle %s"%id
self.pagestyles.append(style)
newstyle = self.book.create_page_style(**self.process_attrib(style))
elif stylename == 'blockstyle':
for e in self.blockstyles:
if self.equal_attrib(e, style):
#print "making blockstyle %s alias to %s"%(id, e.attrib['objid'])
newstyle = self.dobjects[e.attrib['objid']]
break
if newstyle == None:
#print "making blockstyle %s"%id
self.blockstyles.append(style)
newstyle = self.book.create_block_style(**self.process_attrib(style))
elif stylename == 'textstyle':
for e in self.textstyles:
if self.equal_attrib(e, style):
#print "making textstyle %s alias to %s"%(id, e.attrib['objid'])
newstyle = self.dobjects[e.attrib['objid']]
break
if newstyle == None:
#print "making textstyle %s"%id
self.textstyles.append(style)
newstyle = self.book.create_text_style(**self.process_attrib(style))
else:
raise LrsError, "no handler for %s style name"
self.dobjects[id] = newstyle
return newstyle
#
# get and parse a header or footer element
#
def fetch_header_footer(self, element, hfname):
"""get the header/footer element referenced by hfname in element.attrib"""
if hfname not in element.attrib:
return None
id = element.attrib[hfname]
if id in self.dobjects:
return self.dobjects[id]
hf = self.get_element_by_objid(id)
if hf == None:
raise LrsError, "no %s element found for objid=%s"%(hfname, id)
#print "found header/footer type %s with objid = %s after getting %s"%(hf.tag, hf.attrib['objid'], id)
newhf = None
if hfname == 'evenheaderid' or hfname == 'oddheaderid':
for e in self.headers:
if self.equal_header_footer(e, hf):
#print "making header/footer %s alias to %s"%(id, e.attrib['objid'])
newhf = self.dobjects[e.attrib['objid']]
break
if newhf == None:
#print "making header %s"%id
self.headers.append(hf)
newhf = self.process_Header(hf)
elif hfname == 'evenfooterid' or hfname == 'oddfooterid':
for e in self.footers:
if self.equal_header_footer(e, hf):
#print "making footer %s alias to %s"%(id, e.attrib['objid'])
newhf = self.dobjects[e.attrib['objid']]
break
if newhf == None:
#print "making footer %s"%id
self.footers.append(hf)
newhf = self.process_Footer(hf)
else:
raise LrsError, "no handler for %s header/footer name"
self.dobjects[id] = newhf
return newhf
#
# these mostly ignore the terminal elements, should be errors in the end
#
def process_leaf(self, element):
raise LrsError, "process leaf element %s???"%element.tag
def process_empty(self, element):
if element.text or element.getchildren():
raise LrsError, "element %s is not empty???"%element.tag
#
# elements referenced by sets of text elements
#
# def process_Rubi(rubi):
# """Process <Rubi> element"""
# for element in rubi:
# if element.tag == "Oyamoji":
# process_simple_char0(element)
# elif element.tag == "Rubimoji":
# process_simple_char0(element)
# else:
# print "No <Rubi> processor for ", element.tag
#
# def process_AltString(altString):
# """Process <AltString> element"""
# for element in altString:
# if element.tag == "Org":
# process_text(element)
# elif element.tag == "Alt":
# process_text(element)
# else:
# print "No <AltString> processor for ", element.tag
#
# sets of text elements
#
def process_text(self, text, obj):
"""process an element as text"""
if text.text != None:
obj.append(Text(text.text))
for element in text:
print "No text processor for ", element.tag
if element.tail != None:
obj.append(Text(element.tail))
return obj
def process_draw_char(self, draw_char, obj):
"""Process an element in the DrawChar set"""
if draw_char.text != None:
obj.append(Text(draw_char.text))
for element in draw_char:
if element.tag == "Span":
obj.append(self.process_draw_char(element, Span(**element.attrib)))
elif element.tag == "Plot":
obj.append(self.process_text(element, Plot(**element.attrib)))
elif element.tag == "CR":
obj.append(CR())
elif element.tag == "Space":
obj.append(Space(**element.attrib))
elif element.tag == "CharButton":
self.charbuttons.append(element)
element.lrscharbutton = CharButton(None, **self.process_attrib(element))
obj.append(self.process_simple_char1(element, element.lrscharbutton))
elif element.tag == "Sup":
obj.append(self.process_simple_char0(element, Sup(element.text)))
elif element.tag == "Sub":
obj.append(self.process_simple_char0(element, Sub(element.text)))
elif element.tag == "NoBR":
obj.append(self.process_simple_char1(element, NoBR()))
elif element.tag == "DrawChar":
obj.append(self.process_simple_char0(element, DropCaps(**element.attrib)))
elif element.tag == "Box":
obj.append(self.process_simple_char0(element, Box(**element.attrib)))
elif element.tag == "Italic":
obj.append(self.process_draw_char(element, Italic()))
elif element.tag == "Bold":
obj.append(self.process_draw_char(element, Bold()))
# elif element.tag == "Fill":
# obj.append(Fill(**element.attrib))
# elif element.tag == "Rubi":
# obj.append(process_Rubi(element))
# elif element.tag == "Yoko":
# obj.append(process_simple_char0(element, Yoko(**element.attrib)))
# elif element.tag == "Tate":
# obj.append(process_simple_char2(element, Tate(**element.attrib)))
# elif element.tag == "Nekase":
# obj.append(process_simple_char2(element, Nekase(**element.attrib)))
# elif element.tag == "EmpLine":
# obj.append(process_simple_char0(element, EmpLine(**element.attrib)))
# elif element.tag == "EmpDots":
# obj.append(process_simple_char0(element, EmpDots(**element.attrib)))
# elif element.tag == "Gaiji":
# obj.append(process_text(element, Gaiji(**element.attrib)))
# elif element.tag == "AltString":
# obj.append(process_AltString(element))
else:
print "No DrawChar set processor for ", element.tag
if element.tail != None:
obj.append(Text(element.tail))
return obj
def process_simple_char0(self, simple_char0, obj):
"""Process an element in the SimpleChar0 set"""
if simple_char0.text != None:
obj.append(Text(simple_char0.text))
for element in simple_char0:
# if element.tag == "Gaiji":
# obj.append(process_text(element, Gaiji(**element.attrib)))
# elif element.tag == "AltString":
# obj.append(process_AltString(element))
# else:
print "No SimpleChar0 set processor for ", element.tag
if element.tail != None:
obj.append(Text(element.tail))
return obj
def process_simple_char1(self, simple_char1, obj):
"""Process an element in the SimpleChar1 set"""
if simple_char1.text != None:
obj.append(Text(simple_char1.text))
for element in simple_char1:
if element.tag == "Box":
obj.append(self.process_simple_char0(element), Box(**element.attrib))
elif element.tag == "Sub":
obj.append(self.process_simple_char0(element, Sub(**element.attrib)))
elif element.tag == "Sup":
obj.append(self.process_simple_char0(element, Sup(**element.attrib)))
elif element.tag == "Space":
obj.append(Space(**element.attrib))
# elif element.tag == "Rubi":
# obj.append(process_Rubi(element))
# elif element.tag == "Gaiji":
# obj.append(process_text(element, Gaiji(**element.attrib)))
# elif element.tag == "EmpDots":
# obj.append(process_simple_char0(element, EmpDots(**element.attrib)))
# elif element.tag == "EmpLine":
# obj.append(process_simple_char0(element, EmpLine(**element.attrib)))
# elif element.tag == "AltString":
# obj.append(process_AltString(element))
else:
print "No SimpleChar1 set processor for ", element.tag
if element.tail != None:
obj.append(Text(element.tail))
return obj
def process_simple_char2(self, simple_char2, obj):
"""Process an element in the SimpleChar2 set"""
if simple_char2.text != None:
obj.append(Text(simple_char2.text))
for element in simple_char2:
if element.tag == "Plot":
obj.append(self.process_text(element, Plot(**element.attrib)))
# elif element.tag == "Gaiji":
# obj.append(process_text(element, Gaiji(**element.attrib)))
# elif element.tag == "AltString":
# obj.append(process_AltString(element))
else:
print "No SimpleChar2 set processor for ", element.tag
if element.tail != None:
obj.append(Text(element.tail))
return obj
#
# <Canvas> occurs in <Page>, <Objects>, <Window>
#
def process_Canvas(self, canvas):
"""Process the <Canvas> element"""
dcanvas = Canvas(**canvas.attrib)
# text permitted?
for element in canvas:
if element.tag == "PutObj":
dcanvas.append(PutObj(**element.attrib))
# elif element.tag == "MoveTo":
# dcanvas.append(MoveTo(**element.attrib))
# elif element.tag == "LineTo":
# dcanvas.append(LineTo(**element.attrib))
# elif element.tag == "DrawBox":
# dcanvas.append(DrawBox(**element.attrib))
# elif element.tag == "DrawEllipse":
# dcanvas.append(DrawEllipse(**element.attrib))
else:
print "No <Canvas> processor for ", element.tag
# tail text permitted?
return dcanvas
#
# <TextBlock> occurs in <Page>, <Objects>, <Window>, <PopUpWin>
#
def process_TextBlock(self, textBlock):
"""Process the <TextBlock> element"""
self.dobjects[textBlock.attrib['objid']] = \
dtextblock = self.book.create_text_block(textStyle=self.fetch_style(textBlock, 'textstyle'),
blockStyle=self.fetch_style(textBlock, 'blockstyle'),
**self.process_attrib(textBlock))
# text permitted?
for element in textBlock:
if element.tag == "P":
dtextblock.append(self.process_draw_char(element, Paragraph()))
elif element.tag == "CR":
dtextblock.append(CR())
else:
print "No <TextBlock> processor for ", element.tag
# tail text permitted?
return dtextblock
#
# helper for buttons
#
def process_some_Button(self, button, dbutton, name):
# text permitted?
for element in button:
if element.tag == "JumpTo":
refobj = element.attrib['refobj']
if refobj in self.dobjects:
dbutton.append(JumpTo(self.dobjects[refobj]))
else:
self.jumptos.append(element)
element.lrsjumpto = JumpTo(None)
dbutton.append(element.lrsjumpto)
#elif element.tag == "Run":
# dbutton.append(Run(**element.attrib))
#elif element.tag == "SoundStop":
# dbutton.append(SoundStop(**element.attrib))
#elif element.tag == "CloseWindow":
# dbutton.append(CloseWindow(**element.attrib))
else:
print "No ", name, " processor for ", element.tag
# tail text permitted?
return dbutton
#
# <PushButton> occurs in <ButtonBlock>, <Button>
#
def process_PushButton(self, button):
"""Process the <PushButton> element"""
return self.process_some_Button(button, PushButton(**button.attrib), "<PushButton>")
#
# <FocusinButton> occurs in <ButtonBlock>, <Button>
#
#def process_FocusinButton(self, button):
# """Process the <FocusinButton> element"""
# return self.process_some_Button(button, FocusinButton(**button.attrib), "<FocusinButton>")
#
# <UpButton> occurs in <ButtonBlock>, <Button>
#
#def process_UpButton(self, button):
# """Process the <FocusinButton> element"""
# return self.process_some_Button(button, UpButton(**button.attrib), "<UpButton>")
#
# <ButtonBlock> occurs in <Page>, <Objects>, <Window>
#
def process_ButtonBlock(self, buttonBlock):
"""Process the <ButtonBlock> element"""
dbuttonblock = ButtonBlock()
# text permitted?
for element in buttonBlock:
#if element.tag == "BaseButton":
# dbuttonblock.append(BaseButton(**element.attrib))
#elif element.tag == "FocusinButton":
# dbuttonblock.append(process_FocusinButton(element))
#elif element.tag == "PushButton":
# dbuttonblock.append(process_PushButton(element))
#elif element.tag == "UpButton":
# dbuttonblock.append(process_UpButton(element))
#else:
print "No <ButtonBlock> processor for ", element.tag
# tail text permitted?
return dbuttonblock
#
# <Button> occurs at toplevel, also <Page>, <Objects>, <Window>
#
def process_Button(self, button):
"""Process the <Button> element"""
self.dobjects[button.attrib['objid']] = \
dbutton = Button(**self.process_attrib(button))
# text permitted?
for element in button:
#if element.tag == "BaseButton":
# dbutton.append(BaseButton(**element.attrib))
#elif element.tag == "FocusinButton":
# dbutton.append(self.process_FocusinButton(element))
#elif element.tag == "PushButton":
# dbutton.append(self.process_PushButton(element))
#elif element.tag == "UpButton":
# dbutton.append(self.process_UpButton(element))
#else:
print "No <ButtonBlock> processor for ", element.tag
# tail text permitted?
return dbutton
#
# <Page> occurs in <Main>, <PageTree>#
#
def process_Page(self, page):
"""Process the <Page> element"""
attrib = self.process_attrib(page)
for name in ['evenfooter', 'evenheader', 'footer', 'header', 'oddfooter', 'oddheader' ]:
if name+'id' in page.attrib:
attrib[name] = self.fetch_header_footer(page, name+'id')
self.dobjects[page.attrib['objid']] = \
dpage = self.book.create_page(pageStyle=self.fetch_style(page, 'pagestyle'), **attrib)
# text permitted?
for element in page:
if element.tag == "TextBlock":
dpage.append(self.process_TextBlock(element))
elif element.tag == "ImageBlock":
dpage.append(self.process_text(element, ImageBlock(**element.attrib)))
elif element.tag == "ButtonBlock":
dpage.append(self.process_ButtonBlock(element))
elif element.tag == "Button":
dpage.append(self.process_Button(element))
elif element.tag == "BlockSpace":
dpage.BlockSpace(**element.attrib)
elif element.tag == "Canvas":
dpage.append(self.process_Canvas(element))
elif element.tag == "RuledLine":
dpage.append(RuledLine(**element.attrib))
#elif element.tag == "Wait":
# dpage.append(Wait(**element.attrib))
else:
print "No <Page> processor for ", element.tag
# tail text permitted?
return dpage
# <Header> occurs in <Objects>
def process_Header(self,header):
"""Process <Header> element"""
dheader = Header(**self.process_attrib(header))
for element in header:
if element.tag == "PutObj":
self.putobjs.append(element)
element.lrsputobj = PutObj(None, **self.process_attrib(element))
dheader.append(element.lrsputobj)
# elif element.tag == "MoveTo":
# dheader.append(MoveTo(**element.attrib))
# elif element.tag == "LineTo":
# dheader.append(LineTo(**element.attrib))
# elif element.tag == "DrawBox":
# dheader.append(DrawBox(**element.attrib))
# elif element.tag == "DrawEllipse":
# dheader.append(DrawEllipse(**element.attrib))
else:
print "No <Header> processor for ", element.tag
return dheader
# <Footer> occurs in <Objects>
def process_Footer(self, footer):
"""Process <Foother> element"""
dfooter = Footer(**self.process_attrib(footer))
for element in footer:
if element.tag == "PutObj":
self.putobjs.append(element)
element.lrsputobj = PutObj(None, **self.process_attrib(element))
dfooter.append(element.lrsputobj)
# elif element.tag == "MoveTo":
# dheader.append(MoveTo(**element.attrib))
# elif element.tag == "LineTo":
# dheader.append(LineTo(**element.attrib))
# elif element.tag == "DrawBox":
# dheader.append(DrawBox(**element.attrib))
# elif element.tag == "DrawEllipse":
# dheader.append(DrawEllipse(**element.attrib))
else:
print "No <Footer> processor for ", element.tag
return dfooter
#
# Toplevel elements.
#
#
# <BookInformation> occurs at toplevel
#
def process_BookInformation(self, bookInformation):
"""Process the <BookInformation> element"""
dbookinformation = self.book.delegates[0]
def process_Info(info):
"""Process the <Info> element"""
dinfo = dbookinformation.delegates[0]
def process_BookInfo(bookInfo):
"""Process the <BookInfo> element"""
dbookinfo = dinfo.delegates[0]
for element in bookInfo:
if element.tag == "Title":
dbookinfo.title = (element.text, element.get("reading"))
elif element.tag == "Author":
dbookinfo.author = (element.text, element.get("reading"))
elif element.tag == "BookID":
dbookinfo.bookid = element.text
elif element.tag == "Publisher":
dbookinfo.publisher = element.text
elif element.tag == "Label":
dbookinfo.label = element.text
elif element.tag == "Category":
dbookinfo.category = element.text
elif element.tag == "Classification":
dbookinfo.classification = element.text
elif element.tag == "FreeText":
dbookinfo.freetext = element.text
else:
print "No <BookInfo> processor for ", element.tag
def process_DocInfo(docInfo):
"""Process the <DocInfo> element"""
ddocinfo = dinfo.delegates[1]
for element in docInfo:
if element.tag == "Language":
ddocinfo.language = element.text
elif element.tag == "Creator":
ddocinfo.creator = element.text
elif element.tag == "CreationDate":
ddocinfo.creationdate = element.text
elif element.tag == "Producer":
ddocinfo.producer = element.text
elif element.tag == "SumPage":
ddocinfo.numberofpages = element.text
elif element.tag == "CThumbnail":
self.book.delegates[0].delegates[0].delegates[1].thumbnail = element.text
else:
print "No <DocInfo> processor for ", element.tag
for element in info:
if element.tag == "BookInfo":
process_BookInfo(element)
elif element.tag == "DocInfo":
process_DocInfo(element)
# elif element.tag == "Keyword":
# # <Keyword>*
# process_text(element)
else:
print "No <Info> processor for ", element.tag
def process_TOC(toc):
"""Process the <TOC> element in <BookInformation>"""
self.tocs.append(toc)
for element in toc:
if element.tag != "TocLabel":
print "No <TOC> Processor for ", element.tag
for element in bookInformation:
if element.tag == "Info":
process_Info(element)
elif element.tag == "TOC":
process_TOC(element)
else:
print "No <BookInformation> processor for ", element.tag
#
# <Main> occurs in toplevel
#
def process_Main(self, main):
"""Process the <Main> element"""
# merge atrib onto existing Main element
for element in main:
if element.tag == "Page":
self.book.appendPage(self.process_Page(element))
else:
print "No <Main> processor for ", element.tag
#
# <PageTree> occurs in toplevel
#
def process_PageTree(self, pageTree):
"""Process the <PageTree> element"""
dpagetree = self.book.delegates[4].Solo(**pageTree.attrib)
for element in pageTree:
if element.tag == "Page":
dpagetree.appendPage(self.process_Page(element))
else:
print "No <PageTree> processor for ", element.tag
#
# <Style> occurs in toplevel
#
def process_Style(self, style):
"""Process the <Style> element"""
dstyle = self.book.delegates[3]
def process_BookStyle(bookStyle):
"""Process the <BookStyle> element"""
dbookstyle = dstyle.delegates[0]
for element in bookStyle:
if element.tag == "SetDefault":
dbookstyle.styledefault = StyleDefault(**element.attrib)
elif element.tag == "BookSetting":
dbookstyle.booksetting = BookSetting(**element.attrib)
else:
print "No <BookStyle> processor for ", element.tag
for element in style:
if element.tag == "BookStyle":
process_BookStyle(element)
elif element.tag == "PageStyle":
# ignore - self.book.append(PageStyle(**element.attrib))
None
elif element.tag == "TextStyle":
# ignore - self.book.append(TextStyle(**element.attrib))
None
elif element.tag == "BlockStyle":
# ignore - self.book.append(BlockStyle(**element.attrib))
None
else:
print "No <Style> processor for ", element.tag
#
# <Objects> occurs at toplevel
#
def process_Objects(self, objects):
"""Process the <Objects> element"""
dobjects = self.book.delegates[5]
# <Window> occurs in <Objects>
# def process_Window(window):
# """Process the <Window> element"""
#
# dwindow = Window(**window.attrib)
#
# for element in window:
# if element.tag == "TextBlock":
# dwindow.append(process_TextBlock(element))
# elif element.tag == "ImageBlock":
# dwindow.append(process_text(element, ImageBlock(**element.attrib)))
# elif element.tag == "ButtonBlock":
# dwindow.append(process_ButtonBlock(element))
# elif element.tag == "Button":
# dwindow.append(process_Button(element))
# elif element.tag == "Canvas":
# dwindow.append(process_Canvas(element))
# elif element.tag == "RuledLine":
# dwindow.append(RuledLine(**element.attrib))
# elif element.tag == "Wait":
# dwindow.append(Wait(**element.attrib))
# else:
# print "No <Window> processor for ", element.tag
# <PopUpWin> occurs in <Objects>
# def process_PopUpWin(popUpWin):
# """Process <PopUpWin> element"""
# dpopupwin = PopUpWin(**popUpWin.attrib)
# for element in popUpWin:
# if element.tag == "TextBlock":
# dpopupwin.append(process_TextBlock(element))
# elif element.tag == "ImageBlock":
# dpopup.append(process_text(element, ImageBlock(**element.attrib)))
# else:
# print "No <PopUpWin> processor for ", element.tag
# <TOC> doesn't occur in <Objects>, but we try it
# def process_TOC(toc):
# """Process the <TOC> element in <Objects>"""
# for element in toc:
# if element.tag == "TocLabel":
# # problem here, the pylrs TocLabel wants the textBlock
# # not the refobj and refpage that are the specified attributes of the TocLabel
# process_leaf(element)
# else:
# print "No <TOC> Processor for ", element.tag
for element in objects:
if element.tag == "TextBlock":
dobjects.append(self.process_TextBlock(element))
elif element.tag == "ImageBlock":
dobjects.appendImageBlock(self.process_text(element, ImageBlock(**element.attrib)))
elif element.tag == "ButtonBlock":
dobjects.append(self.process_ButtonBlock(element))
elif element.tag == "Button":
dobjects.append(self.process_Button(element))
elif element.tag == "Canvas":
dobjects.append(self.process_Canvas(element))
# elif element.tag == "Window":
# dobjects.appendWindow(process_Window(element))
# elif element.tag == "PopUpWin":
# dobjects.appendPopUpWin(process_PopUpWin(element))
# elif element.tag == "Sound":
# dobjects.appendSound(self.process_empty(element))
# elif element.tag == "SoundStream":
# dobjects.appendSoundStream(self.process_empty(element))
elif element.tag == "ImageStream":
dobjects.appendImageStream(self.process_text(element, ImageStream(**element.attrib)))
elif element.tag == "Header":
# processed as part of Page or PageStyle, just skip here
None # self.process_Header(element)
elif element.tag == "Footer":
# processed as part of Page or PageStyle
None # self.process_Footer(element)
# elif element.tag == "eSound":
# dobjects.appendeSound(process_empty(element))
elif element.tag == "Image":
dobjects.appendImage(self.process_text(element, Image(**element.attrib)))
# elif element.tag == "TOC":
# dobjects.appendTOC(process_TOC(element))
else:
print "No <Objects> processor for ", element.tag
#
#
#
def process_file(self):
# Iterate
for element in self.root.getroot():
# switch on element.tag
if element.tag == "Property":
self.process_empty(element)
elif element.tag == "BookInformation":
self.process_BookInformation(element)
elif element.tag == "Main":
self.process_Main(element)
elif element.tag == "PageTree":
self.process_PageTree(element)
elif element.tag == "Template":
self.process_empty(element)
elif element.tag == "Style":
self.process_Style(element)
elif element.tag == "Objects":
self.process_Objects(element)
else:
print "\tNo toplevel processor for ", element.tag
# Post processing
for toc in self.tocs:
for tocLabel in toc:
refobj = tocLabel.attrib['refobj']
if refobj not in self.dobjects:
raise LrsError, "TocLabel reference to %s did not resolve"%refobj
else:
self.book.addTocEntry(tocLabel.text, self.dobjects[refobj])
for cb in self.charbuttons:
refobj = cb.attrib['refobj']
if refobj not in self.dobjects:
raise LrsError, "CharButton reference to %s did not resolve"%refobj
else:
cb.lrscharbutton.setButton(self.dobjects[refobj])
for jt in self.jumptos:
refobj = jt.attrib['refobj']
if refobj not in self.dobjects:
raise LrsError, "JumpTo reference to %s did not resolve"%refobj
else:
jt.lrsjumpto.setTextBlock(self.dobjects[refobj])
for po in self.putobjs:
refobj = po.attrib['refobj']
if refobj not in self.dobjects:
raise LrsError, "PutObj reference to %s did not resolve"%refobj
else:
po.lrsputobj.setContent(self.dobjects[refobj])
def renderLrf(self, file):
self.book.renderLrf(file)
def renderLrs(self, file):
self.book.renderLrs(file)
def option_parser():
from optparse import OptionParser
parser = OptionParser(usage='%prog [options] file.lrs',
version=__appname__+ ' ' + __version__,
epilog='Created by Roger Critchlow')
parser.add_option('-o', '--output', default=None, help='Path to output file')
parser.add_option('--verbose', default=False, action='store_true',
help='Verbose processing')
parser.add_option('--lrs', default=False, action='store_true',
help='Convert LRS to LRS, useful for debugging.')
return parser
def main(args=sys.argv):
parser = option_parser()
opts, args = parser.parse_args(args)
if len(args) != 2:
parser.print_help()
return 1
if not opts.output:
ext = '.lrs' if opts.lrs else '.lrf'
opts.output = os.path.splitext(os.path.basename(args[1]))[0]+ext
opts.output = os.path.abspath(opts.output)
if opts.verbose:
import warnings
warnings.defaultaction = 'error'
converter = LrsParser(args[1])
converter.process_file()
if opts.lrs:
converter.renderLrs(opts.output)
else:
converter.renderLrf(opts.output)
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@ -1,11 +1,13 @@
""" elements.py -- replacements and helpers for ElementTree """ """ elements.py -- replacements and helpers for ElementTree """
class ElementWriter(object): class ElementWriter(object):
def __init__(self, e, header=False, sourceEncoding="ascii", spaceBeforeClose=True): def __init__(self, e, header=False, sourceEncoding="ascii",
spaceBeforeClose=True, outputEncodingName="UTF-16"):
self.header = header self.header = header
self.e = e self.e = e
self.sourceEncoding=sourceEncoding self.sourceEncoding=sourceEncoding
self.spaceBeforeClose = spaceBeforeClose self.spaceBeforeClose = spaceBeforeClose
self.outputEncodingName = outputEncodingName
def _encodeCdata(self, rawText): def _encodeCdata(self, rawText):
@ -71,8 +73,8 @@ class ElementWriter(object):
def write(self, f): def write(self, f):
if self.header: if self.header:
f.write(u'<?xml version="1.0" encoding="UTF-16"?>\n') f.write(u'<?xml version="1.0" encoding="%s"?>\n' % self.outputEncodingName)
self._write(f, self.e) self._write(f, self.e)

View File

@ -368,7 +368,7 @@ class Book(Delegator):
The following settings are available on the contructor of Book: The following settings are available on the contructor of Book:
author="book author" or author=("book author, "sort as") author="book author" or author=("book author", "sort as")
Author of the book. Author of the book.
title="book title" or title=("book title", "sort as") title="book title" or title=("book title", "sort as")
@ -1665,7 +1665,7 @@ class LrsSimpleChar1(object):
class DropCaps(LrsTextTag): class DropCaps(LrsTextTag):
def __init__(self, lines): def __init__(self, lines=1):
LrsTextTag.__init__(self, None, [LrsSimpleChar1]) LrsTextTag.__init__(self, None, [LrsSimpleChar1])
if int(lines) <= 0: if int(lines) <= 0:
raise LrsError('A DrawChar must span at least one line.') raise LrsError('A DrawChar must span at least one line.')
@ -1685,10 +1685,70 @@ class DropCaps(LrsTextTag):
parent.appendLrfTag(LrfTag("DrawCharEnd")) parent.appendLrfTag(LrfTag("DrawCharEnd"))
class Button(object): class Button(LrsObject, LrsContainer):
# TODO: Implement def __init__(self, **settings):
LrsObject.__init__(self, **settings)
LrsContainer.__init__(self, [PushButton])
def findJumpToRefs(self):
for sub1 in self.contents:
if isinstance(sub1, PushButton):
for sub2 in sub1.contents:
if isinstance(sub2, JumpTo):
return (sub2.textBlock.objId, sub2.textBlock.parent.objId)
raise LrsException, "%s has no PushButton or JumpTo subs"%self.__class__.__name__
def toLrf(self, lrfWriter):
(refobj, refpage) = self.findJumpToRefs()
# print "Button writing JumpTo refobj=", jumpto.refobj, ", and refpage=", jumpto.refpage
button = LrfObject("Button", self.objId)
button.appendLrfTag(LrfTag("buttonflags", 0x10)) # pushbutton
button.appendLrfTag(LrfTag("PushButtonStart"))
button.appendLrfTag(LrfTag("buttonactions"))
button.appendLrfTag(LrfTag("jumpto", (int(refpage), int(refobj))))
button.append(LrfTag("endbuttonactions"))
button.appendLrfTag(LrfTag("PushButtonEnd"))
lrfWriter.append(button)
def toElement(self, se):
b = self.lrsObjectElement("Button")
for content in self.contents:
b.append(content.toElement(se))
return b
class ButtonBlock(Button):
pass pass
class PushButton(LrsContainer):
def __init__(self, **settings):
LrsContainer.__init__(self, [JumpTo])
def toElement(self, se):
b = Element("PushButton")
for content in self.contents:
b.append(content.toElement(se))
return b
class JumpTo(LrsContainer):
def __init__(self, textBlock):
LrsContainer.__init__(self, [])
self.textBlock=textBlock
def setTextBlock(self, textBlock):
self.textBlock = textBlock
def toElement(self, se):
return Element("JumpTo", refpage=str(self.textBlock.parent.objId), refobj=str(self.textBlock.objId))
class Plot(LrsSimpleChar1, LrsContainer): class Plot(LrsSimpleChar1, LrsContainer):
@ -1964,27 +2024,33 @@ class CharButton(LrsSimpleChar1, LrsContainer):
Only text or SimpleChars can be appended to the CharButton. Only text or SimpleChars can be appended to the CharButton.
""" """
def __init__(self, jumpButton, text=None): def __init__(self, button, text=None):
LrsContainer.__init__(self, [basestring, Text, LrsSimpleChar1]) LrsContainer.__init__(self, [basestring, Text, LrsSimpleChar1])
if not isinstance(jumpButton, JumpButton): self.button = None
raise LrsError, "first argument to CharButton must be a JumpButton" if button != None:
self.setButton(button)
self.jumpButton = jumpButton
if text is not None: if text is not None:
self.append(text) self.append(text)
def setButton(self, button):
if not isinstance(button, (JumpButton, Button)):
raise LrsError, "CharButton button must be a JumpButton or Button"
self.button = button
def appendReferencedObjects(self, parent): def appendReferencedObjects(self, parent):
if self.jumpButton.parent is None: if self.button.parent is None:
parent.append(self.jumpButton) parent.append(self.button)
def getReferencedObjIds(self): def getReferencedObjIds(self):
return [self.jumpButton.objId] return [self.button.objId]
def toLrfContainer(self, lrfWriter, container): def toLrfContainer(self, lrfWriter, container):
container.appendLrfTag(LrfTag("CharButton", self.jumpButton.objId)) container.appendLrfTag(LrfTag("CharButton", self.button.objId))
for content in self.contents: for content in self.contents:
content.toLrfContainer(lrfWriter, container) content.toLrfContainer(lrfWriter, container)
@ -1993,7 +2059,7 @@ class CharButton(LrsSimpleChar1, LrsContainer):
def toElement(self, se): def toElement(self, se):
cb = Element("CharButton", refobj=str(self.jumpButton.objId)) cb = Element("CharButton", refobj=str(self.button.objId))
appendTextElements(cb, self.contents, se) appendTextElements(cb, self.contents, se)
return cb return cb
@ -2002,7 +2068,7 @@ class CharButton(LrsSimpleChar1, LrsContainer):
class Objects(LrsContainer): class Objects(LrsContainer):
def __init__(self): def __init__(self):
LrsContainer.__init__(self, [JumpButton, TextBlock, HeaderOrFooter, LrsContainer.__init__(self, [JumpButton, TextBlock, HeaderOrFooter,
ImageStream, Image, ImageBlock]) ImageStream, Image, ImageBlock, Button, ButtonBlock])
self.appendJumpButton = self.appendTextBlock = self.appendHeader = \ self.appendJumpButton = self.appendTextBlock = self.appendHeader = \
self.appendFooter = self.appendImageStream = \ self.appendFooter = self.appendImageStream = \
self.appendImage = self.appendImageBlock = self.append self.appendImage = self.appendImageBlock = self.append
@ -2084,7 +2150,9 @@ class JumpButton(LrsObject, LrsContainer):
LrsContainer.__init__(self, []) LrsContainer.__init__(self, [])
self.textBlock = textBlock self.textBlock = textBlock
def setTextBlock(self, textBlock):
self.textBlock = textBlock
def toLrf(self, lrfWriter): def toLrf(self, lrfWriter):
button = LrfObject("Button", self.objId) button = LrfObject("Button", self.objId)
button.appendLrfTag(LrfTag("buttonflags", 0x10)) # pushbutton button.appendLrfTag(LrfTag("buttonflags", 0x10)) # pushbutton
@ -2202,7 +2270,7 @@ class Canvas(LrsObject, LrsContainer, LrsAttributes):
self.settings['canvaswidth'] = int(width) self.settings['canvaswidth'] = int(width)
def put_object(self, obj, x, y): def put_object(self, obj, x, y):
self.append(PutObj(obj, x=x, y=y)) self.append(PutObj(obj, x1=x, y1=y))
def toElement(self, source_encoding): def toElement(self, source_encoding):
el = self.lrsObjectElement("Canvas", **self.settings) el = self.lrsObjectElement("Canvas", **self.settings)
@ -2235,18 +2303,19 @@ class Canvas(LrsObject, LrsContainer, LrsAttributes):
class PutObj(LrsContainer): class PutObj(LrsContainer):
""" PutObj holds other objects that are drawn on a Canvas or Header. """ """ PutObj holds other objects that are drawn on a Canvas or Header. """
def __init__(self, content, x=0, y=0): def __init__(self, content, x1=0, y1=0):
LrsContainer.__init__(self, [TextBlock, ImageBlock]) LrsContainer.__init__(self, [TextBlock, ImageBlock])
self.content = content self.content = content
self.x1 = int(x) self.x1 = int(x1)
self.y1 = int(y) self.y1 = int(y1)
def setContent(self, content):
self.content = content
def appendReferencedObjects(self, parent): def appendReferencedObjects(self, parent):
if self.content.parent is None: if self.content.parent is None:
parent.append(self.content) parent.append(self.content)
def toLrfContainer(self, lrfWriter, container): def toLrfContainer(self, lrfWriter, container):
container.appendLrfTag(LrfTag("PutObj", (self.x1, self.y1, container.appendLrfTag(LrfTag("PutObj", (self.x1, self.y1,
self.content.objId))) self.content.objId)))

View File

@ -51,6 +51,7 @@ class Distribution(object):
('dbus-python', '0.82.2', 'dbus-python', 'python-dbus', 'dbus-python'), ('dbus-python', '0.82.2', 'dbus-python', 'python-dbus', 'dbus-python'),
('convertlit', '1.8', 'convertlit', None, None), ('convertlit', '1.8', 'convertlit', None, None),
('lxml', '1.3.3', 'lxml', 'python-lxml', 'python-lxml'), ('lxml', '1.3.3', 'lxml', 'python-lxml', 'python-lxml'),
('elementtree', '1.2.6', 'elementtree', 'python-elementtree', 'python-elementtree'),
] ]
DISTRO_MAP = {'gentoo':2, 'ubuntu':3, 'fedora':4, 'debian':3} DISTRO_MAP = {'gentoo':2, 'ubuntu':3, 'fedora':4, 'debian':3}