diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 2228424782..fd69a3745a 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -302,6 +302,7 @@ from calibre.web.feeds.input import RecipeInput from calibre.ebooks.oeb.output import OEBOutput from calibre.ebooks.epub.output import EPUBOutput from calibre.ebooks.mobi.output import MOBIOutput +from calibre.ebooks.pdb.output import PDBOutput from calibre.ebooks.lrf.output import LRFOutput from calibre.ebooks.lit.output import LITOutput from calibre.ebooks.txt.output import TXTOutput @@ -323,7 +324,7 @@ from calibre.devices.jetbook.driver import JETBOOK plugins = [HTML2ZIP, EPUBInput, MOBIInput, PDBInput, PDFInput, HTMLInput, TXTInput, OEBOutput, TXTOutput, PDFOutput, LITInput, ComicInput, FB2Input, ODTInput, RTFInput, EPUBOutput, RecipeInput, PMLInput, - PMLOutput, MOBIOutput, LRFOutput, LITOutput] + PMLOutput, MOBIOutput, PDBOutput, LRFOutput, LITOutput] plugins += [PRS500, PRS505, PRS700, CYBOOKG3, KINDLE, KINDLE2, BLACKBERRY, EB600, JETBOOK] plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ diff --git a/src/calibre/ebooks/pdb/__init__.py b/src/calibre/ebooks/pdb/__init__.py index 1bf8ebeb89..f60cc91c93 100644 --- a/src/calibre/ebooks/pdb/__init__.py +++ b/src/calibre/ebooks/pdb/__init__.py @@ -5,15 +5,25 @@ __license__ = 'GPL v3' __copyright__ = '2009, John Schember ' __docformat__ = 'restructuredtext en' -from calibre.ebooks.pdb.ereader.reader import Reader as eReader -from calibre.ebooks.pdb.ztxt.reader import Reader as zTXT -from calibre.ebooks.pdb.palmdoc.reader import Reader as PalmDoc +class PDBError(Exception): + pass + -FORMATS = { - 'PNPdPPrs' : eReader, - 'PNRdPPrs' : eReader, - 'zTXTGPlm' : zTXT, - 'TEXtREAd' : PalmDoc, +from calibre.ebooks.pdb.ereader.reader import Reader as ereader_reader +from calibre.ebooks.pdb.ztxt.reader import Reader as ztxt_reader +from calibre.ebooks.pdb.palmdoc.reader import Reader as palmdoc_reader + +FORMAT_READERS = { + 'PNPdPPrs' : ereader_reader, + 'PNRdPPrs' : ereader_reader, + 'zTXTGPlm' : ztxt_reader, + 'TEXtREAd' : palmdoc_reader, +} + +from calibre.ebooks.pdb.palmdoc.writer import Writer as palmdoc_writer + +FORMAT_WRITERS = { + 'doc' : palmdoc_writer, } IDENTITY_TO_NAME = { @@ -48,15 +58,15 @@ IDENTITY_TO_NAME = { 'BDOCWrdS' : 'WordSmith', } -class PDBError(Exception): - pass - - def get_reader(identity): ''' Returns None if no reader is found for the identity. ''' - if identity in FORMATS.keys(): - return FORMATS[identity] - else: - return None + return FORMAT_READERS.get(identity, None) + +def get_writer(extension): + ''' + Returns None if no writer is found for extension. + ''' + return FORMAT_WRITERS.get(extension, None) + diff --git a/src/calibre/ebooks/pdb/formatreader.py b/src/calibre/ebooks/pdb/formatreader.py index 25abb462cf..bde6c9ae35 100644 --- a/src/calibre/ebooks/pdb/formatreader.py +++ b/src/calibre/ebooks/pdb/formatreader.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import with_statement + ''' Interface defining the necessary public functions for a pdb format reader. ''' diff --git a/src/calibre/ebooks/pdb/formatwriter.py b/src/calibre/ebooks/pdb/formatwriter.py new file mode 100644 index 0000000000..18b5f56219 --- /dev/null +++ b/src/calibre/ebooks/pdb/formatwriter.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +''' +Interface defining the necessary public functions for a pdb format writer. +''' + +__license__ = 'GPL v3' +__copyright__ = '2009, John Schember ' +__docformat__ = 'restructuredtext en' + + +class FormatWriter(object): + + def __init__(self, opts, log): + raise NotImplementedError() + + def write_content(self, oeb_book, output_stream, ): + raise NotImplementedError() diff --git a/src/calibre/ebooks/pdb/input.py b/src/calibre/ebooks/pdb/input.py index 1a7e32e3eb..68e709e8b8 100644 --- a/src/calibre/ebooks/pdb/input.py +++ b/src/calibre/ebooks/pdb/input.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from __future__ import with_statement __license__ = 'GPL v3' __copyright__ = '2009, John Schember ' diff --git a/src/calibre/ebooks/pdb/output.py b/src/calibre/ebooks/pdb/output.py new file mode 100644 index 0000000000..2095b64ab2 --- /dev/null +++ b/src/calibre/ebooks/pdb/output.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +__license__ = 'GPL 3' +__copyright__ = '2009, John Schember ' +__docformat__ = 'restructuredtext en' + +import os + +from calibre.customize.conversion import OutputFormatPlugin +from calibre.ebooks.pdb import PDBError, get_writer + +class PDBOutput(OutputFormatPlugin): + + name = 'PDB Output' + author = 'John Schember' + file_type = 'pdb' + + def convert(self, oeb_book, output_path, input_plugin, opts, log): + close = False + if not hasattr(output_path, 'write'): + # Determine the format to write based upon the sub extension + format = os.path.splitext(os.path.splitext(output_path)[0])[1][1:] + close = True + if not os.path.exists(os.path.dirname(output_path)) and os.path.dirname(output_path) != '': + os.makedirs(os.path.dirname(output_path)) + out_stream = open(output_path, 'wb') + else: + format = os.path.splitext(os.path.splitext(output_path.name)[0])[1][1:] + out_stream = output_path + + Writer = get_writer(format) + + if Writer is None: + raise PDBError('No writer avaliable for format %s.' % format) + + writer = Writer(opts, log) + + out_stream.seek(0) + out_stream.truncate() + + writer.write_content(oeb_book, out_stream) + + if close: + out_stream.close() + diff --git a/src/calibre/ebooks/pdb/palmdoc/writer.py b/src/calibre/ebooks/pdb/palmdoc/writer.py new file mode 100644 index 0000000000..a93bc94d26 --- /dev/null +++ b/src/calibre/ebooks/pdb/palmdoc/writer.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +''' +Writer content to palmdoc pdb file. +''' + +__license__ = 'GPL v3' +__copyright__ = '2009, John Schember ' +__docformat__ = 'restructuredtext en' + +import struct + +from calibre.ebooks.pdb.formatwriter import FormatWriter +from calibre.ebooks.txt.writer import TxtWriter, TxtNewlines, TxtMetadata +from calibre.ebooks.mobi.palmdoc import compress_doc +from calibre.ebooks.pdb.header import PdbHeaderBuilder + +MAX_RECORD_SIZE = 4096 + +class Writer(FormatWriter): + + def __init__(self, opts, log): + self.opts = opts + self.log = log + + def write_content(self, oeb_book, out_stream): + title = self.opts.title if self.opts.title else oeb_book.metadata.title[0].value if oeb_book.metadata.title != [] else _('Unknown') + + txt_records, txt_length = self._generate_text(oeb_book.spine) + header_record = self._header_record(txt_length, len(txt_records)) + + section_lengths = [len(header_record)] + for i in range(0, len(txt_records)): + txt_records[i] = compress_doc(txt_records[i].encode('utf-8')) + section_lengths.append(len(txt_records[i])) + + out_stream.seek(0) + hb = PdbHeaderBuilder('TEXtREAd', title) + hb.build_header(section_lengths, out_stream) + + for record in [header_record]+txt_records: + out_stream.write(record) + + def _generate_text(self, spine): + txt_writer = TxtWriter(TxtNewlines('system').newline, self.log) + txt = txt_writer.dump(spine, TxtMetadata()) + + txt_length = len(txt) + + txt_records = [] + for i in range(0, (len(txt) / MAX_RECORD_SIZE) + 1): + txt_records.append(txt[i * MAX_RECORD_SIZE : (i * MAX_RECORD_SIZE) + MAX_RECORD_SIZE]) + + return txt_records, txt_length + + def _header_record(self, txt_length, record_count): + record = '' + + record += struct.pack('>H', 2) # [0:2], PalmDoc compression. (1 = No compression). + record += struct.pack('>H', 0) # [2:4], Always 0. + record += struct.pack('>L', txt_length) # [4:8], Uncompressed length of the entire text of the book. + record += struct.pack('>H', record_count) # [8:10], Number of PDB records used for the text of the book. + record += struct.pack('>H', MAX_RECORD_SIZE) # [10-12], Maximum size of each record containing text, always 4096. + record += struct.pack('>L', 0) # [12-16], Current reading position, as an offset into the uncompressed text. + + return record + diff --git a/src/calibre/ebooks/txt/output.py b/src/calibre/ebooks/txt/output.py index 62c07c3d04..219e1d3111 100644 --- a/src/calibre/ebooks/txt/output.py +++ b/src/calibre/ebooks/txt/output.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- + __license__ = 'GPL 3' __copyright__ = '2009, John Schember ' __docformat__ = 'restructuredtext en'