]> xmof Git - DeDRM.git/commitdiff
tools v1.4
authorApprentice Alf <apprenticealf@gmail.com>
Wed, 24 Feb 2010 14:09:01 +0000 (14:09 +0000)
committerApprentice Alf <apprenticealf@gmail.com>
Mon, 2 Mar 2015 07:41:20 +0000 (07:41 +0000)
Adobe_EPUB_Tools/ineptkeymac.pyw [new file with mode: 0644]
Topaz_Tools/lib/convert2xml.py
Topaz_Tools/lib/gensvg.py
eReader_Tools/eReaderPDB2PMLZ.pyw [new file with mode: 0644]
eReader_Tools/lib/erdr2pml.py

diff --git a/Adobe_EPUB_Tools/ineptkeymac.pyw b/Adobe_EPUB_Tools/ineptkeymac.pyw
new file mode 100644 (file)
index 0000000..0dd1307
--- /dev/null
@@ -0,0 +1,123 @@
+#! /usr/bin/env python
+
+# ineptkeymac.py, version 1
+
+# This program runs on Mac OS X, version 10.6.2 and probably several other
+# versions. It uses Python 2.6, but it probably also runs on all versions
+# 2.x with x >= 5.
+
+# This program extracts the private RSA key for your ADE account in a
+# standard binary form (DER format) in a file of your choosing. Its purpose
+# is to make a backup of that key so that your legally bought ADE encoded
+# ebooks can be salvaged in case they would no longer be supported by ADE
+# software. No other usages are intended. 
+
+# It has been tested with the key storage structure of ADE 1.7.1 and 1.7.2
+# and Sony Reader Library.
+
+# This software does not contain any encryption code. Its only use of
+# external encryption software is the use of openssl for the conversion of
+# the private key from pem to der format. It doesn't use encryption or
+# decryption, however.
+
+# You can run this program from the command line (python ineptkeymac.py
+# filename), or by doubleclicking when it has been associated with
+# Pythonlauncher. When no filename is given it will show a dialog to obtain one.
+
+from __future__ import with_statement
+
+__license__ = 'GPL v3'
+
+import sys
+import os
+import xml.etree.ElementTree as etree
+from contextlib import closing
+import Tkinter
+import Tkconstants
+import tkFileDialog
+from tkMessageBox import showerror
+from subprocess import Popen, PIPE
+import textwrap
+
+NS = 'http://ns.adobe.com/adept'
+ACTFILE = '~/Library/Application Support/Adobe/Digital Editions/activation.dat'
+HEADER = '-----BEGIN PRIVATE KEY-----\n'
+FOOTER = '\n-----END PRIVATE KEY-----\n'
+
+Gui = False
+
+def get_key():
+    '''Returns the private key as a binary string (DER format)'''
+    try:
+        filename = os.path.expanduser(ACTFILE)
+        tree = etree.parse(filename)
+        xpath = '//{%s}credentials/{%s}privateLicenseKey' % (NS, NS)
+        b64key = tree.findtext(xpath)
+        pemkey = HEADER + textwrap.fill(b64key, 64) + FOOTER
+        
+        cmd = ['openssl', 'rsa', '-outform', 'der']
+        proc = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
+        stdout, stderr = proc.communicate(pemkey)
+
+        if proc.returncode != 0:
+            error("openssl error: " + stderr)
+            return None
+        return stdout
+            
+    except IOError:
+        error("Can find keyfile. Maybe you should activate your Adobe ID.")
+        sys.exit(1)
+        
+def store_key(key, keypath):
+    '''Store the key in the file given as keypath. If no keypath is given a
+    dialog will ask for one.'''
+    
+    try:
+        if keypath is None:
+            keypath = get_keypath()
+            if not keypath: # Cancelled
+                return
+            
+        with closing(open(keypath, 'wb')) as outf:
+            outf.write(key)
+            
+    except IOError, e:
+        error("Can write keyfile: " + str(e))
+
+def get_keypath():
+    keypath = tkFileDialog.asksaveasfilename(
+        parent = None, title = 'Select file to store ADEPT key',
+        initialdir = os.path.expanduser('~/Desktop'),
+        initialfile = 'adeptkey.der',
+        defaultextension = '.der', filetypes = [('DER-encoded files', '.der'),
+                                                ('All Files', '.*')])
+    if keypath:
+        keypath = os.path.normpath(keypath)
+    return keypath
+
+def error(text):
+    print text
+    if Gui: showerror('Error!', text)
+    
+def gui_main():
+    root = Tkinter.Tk()
+    root.iconify() 
+    global Gui
+    Gui = True
+    store_key(get_key(), None)
+
+    return 0
+    
+def main(argv=sys.argv):
+    progname = os.path.basename(argv[0])
+    
+    if len(argv) == 1: # assume GUI if no argument given
+        return gui_main()
+    if len(argv) != 2:
+        print "usage: %s KEYFILE" % (progname,)
+        return 1
+    
+    store_key(get_key(), argv[1])
+
+if __name__ == '__main__':
+    sys.exit(main())
index 958e3b9b9d57eae37214c1240044e97a48915b0a..18ae3f02ba369c9c97e3e2b4073047954ba46224 100644 (file)
@@ -1,6 +1,6 @@
 #! /usr/bin/python
 # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
-# For use with Topaz Scripts Version 2.3
+# For use with Topaz Scripts Version 2.4
 
 class Unbuffered:
     def __init__(self, stream):
@@ -243,6 +243,8 @@ class PageParser(object):
         'region.h'         : (1, 'scalar_number', 0, 0),
         'region.w'         : (1, 'scalar_number', 0, 0),
 
+        'empty_text_region' : (1, 'snippets', 1, 0),
+
         'img'          : (1, 'snippets', 1, 0),
         'img.x'        : (1, 'scalar_number', 0, 0),
         'img.y'        : (1, 'scalar_number', 0, 0),
index 82f6bc7d333e52e3c446ed89ac5d70d7402d240a..040fe9bbea18bb1d8a0345aafb20420ac7303a66 100644 (file)
@@ -28,15 +28,24 @@ class GParser(object):
      self.gh = self.getData('info.glyph.h')
      self.gw = self.getData('info.glyph.w')
      self.guse = self.getData('info.glyph.use')
-     self.count = len(self.guse)
+     if self.guse :
+         self.count = len(self.guse)
+     else :
+         self.count = 0
      self.gvtx = self.getData('info.glyph.vtx')
      self.glen = self.getData('info.glyph.len')
      self.gdpi = self.getData('info.glyph.dpi')
      self.vx = self.getData('info.vtx.x')
      self.vy = self.getData('info.vtx.y')
      self.vlen = self.getData('info.len.n')
-     self.glen.append(len(self.vlen))
-     self.gvtx.append(len(self.vx))
+     if self.vlen :
+         self.glen.append(len(self.vlen))
+     elif self.glen:
+         self.glen.append(0)
+     if self.vx :
+         self.gvtx.append(len(self.vx))
+     elif self.gvtx :
+         self.gvtx.append(0)
 
  def getData(self, path):
      result = None
diff --git a/eReader_Tools/eReaderPDB2PMLZ.pyw b/eReader_Tools/eReaderPDB2PMLZ.pyw
new file mode 100644 (file)
index 0000000..635f3fe
--- /dev/null
@@ -0,0 +1,180 @@
+#!/usr/bin/env python
+# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
+
+import sys
+sys.path.append('lib')
+
+import os, os.path, urllib
+import subprocess
+from subprocess import Popen, PIPE, STDOUT
+import Tkinter
+import Tkconstants
+import tkFileDialog
+import tkMessageBox
+import subasyncio
+from subasyncio import Process
+from scrolltextwidget import ScrolledText
+
+class MainDialog(Tkinter.Frame):
+    def __init__(self, root):
+        Tkinter.Frame.__init__(self, root, border=5)
+        self.root = root
+        self.interval = 2000
+        self.p2 = None
+        self.status = Tkinter.Label(self, text='eReader eBook Conversion to PMLZ')
+        self.status.pack(fill=Tkconstants.X, expand=1)
+        body = Tkinter.Frame(self)
+        body.pack(fill=Tkconstants.X, expand=1)
+        sticky = Tkconstants.E + Tkconstants.W
+        body.grid_columnconfigure(1, weight=2)
+
+        Tkinter.Label(body, text='eBook PDB input file').grid(row=0, sticky=Tkconstants.E)
+        self.pdbpath = Tkinter.Entry(body, width=50)
+        self.pdbpath.grid(row=0, column=1, sticky=sticky)
+        cwd = os.getcwdu()
+        cwd = cwd.encode('utf-8')
+        self.pdbpath.insert(0, cwd)
+        button = Tkinter.Button(body, text="...", command=self.get_pdbpath)
+        button.grid(row=0, column=2)
+
+        Tkinter.Label(body, text='Name on CC').grid(row=1, sticky=Tkconstants.E)
+        self.name = Tkinter.StringVar()
+        self.nameinfo = Tkinter.Entry(body, width=40, textvariable=self.name)
+        self.nameinfo.grid(row=1, column=1, sticky=sticky)
+
+        Tkinter.Label(body, text='Last 8 digits of CC Number').grid(row=2, sticky=Tkconstants.E)
+        self.ccnum = Tkinter.StringVar()
+        self.ccinfo = Tkinter.Entry(body, width=10, textvariable=self.ccnum)
+        self.ccinfo.grid(row=2, column=1, sticky=sticky)
+
+        msg1 = 'Conversion Log \n\n'
+        self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=15, width=60, wrap=Tkconstants.WORD)
+        self.stext.grid(row=3, column=0, columnspan=2,sticky=sticky)
+        self.stext.insert(Tkconstants.END,msg1)
+
+        buttons = Tkinter.Frame(self)
+        buttons.pack()
+        self.sbotton = Tkinter.Button(
+            buttons, text="Start", width=10, command=self.convertit)
+        self.sbotton.pack(side=Tkconstants.LEFT)
+
+        Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT)
+        self.qbutton = Tkinter.Button(
+            buttons, text="Quit", width=10, command=self.quitting)
+        self.qbutton.pack(side=Tkconstants.RIGHT)
+
+    # read from subprocess pipe without blocking
+    # invoked every interval via the widget "after"
+    # option being used, so need to reset it for the next time
+    def processPipe(self):
+        poll = self.p2.wait('nowait')
+        if poll != None: 
+            text = self.p2.readerr()
+            text += self.p2.read()
+            msg = text + '\n\n' + 'File successfully converted\n'
+            if poll != 0:
+                msg = text + '\n\n' + 'Error: Conversion Failed\n'
+            self.showCmdOutput(msg)
+            self.p2 = None
+            self.sbotton.configure(state='normal')
+            return
+        text = self.p2.readerr()
+        text += self.p2.read()
+        self.showCmdOutput(text)
+        # make sure we get invoked again by event loop after interval 
+        self.stext.after(self.interval,self.processPipe)
+        return
+
+    # post output from subprocess in scrolled text widget
+    def showCmdOutput(self, msg):
+        if msg and msg !='':
+            msg = msg.encode('utf-8')
+            self.stext.insert(Tkconstants.END,msg)
+            self.stext.yview_pickplace(Tkconstants.END)
+        return
+
+    # run erdr2pml.py as a subprocess via pipes and collect stdout
+    def erdr(self, infile, name, ccnum):
+        # os.putenv('PYTHONUNBUFFERED', '1')
+        cmdline = 'python ./lib/erdr2pml.py --make-pmlz "' + infile + '" "' + name + '" ' + ccnum 
+        if sys.platform[0:3] == 'win':
+            search_path = os.environ['PATH']
+            search_path = search_path.lower()
+            if search_path.find('python') >= 0: 
+                cmdline = 'python lib\erdr2pml.py --make-pmlz "' + infile + '" "' + name + '" ' + ccnum
+            else :
+                cmdline = 'lib\erdr2pml.py --make-pmlz "' + infile + '" "' + name + '" ' + ccnum
+
+        cmdline = cmdline.encode(sys.getfilesystemencoding())
+        p2 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
+        return p2
+
+
+    def get_pdbpath(self):
+        pdbpath = tkFileDialog.askopenfilename(
+            parent=None, title='Select eReader PDB File',
+            defaultextension='.pdb', filetypes=[('eReader eBooks', '.pdb'),
+                                                ('All Files', '.*')])
+        if pdbpath:
+            pdbpath = os.path.normpath(pdbpath)
+            self.pdbpath.delete(0, Tkconstants.END)
+            self.pdbpath.insert(0, pdbpath)
+        return
+
+    def quitting(self):
+        # kill any still running subprocess
+        if self.p2 != None:
+            if (self.p2.wait('nowait') == None):
+                self.p2.terminate()
+        self.root.destroy()
+
+    # actually ready to run the subprocess and get its output
+    def convertit(self):
+        # now disable the button to prevent multiple launches
+        self.sbotton.configure(state='disabled')
+        pdbpath = self.pdbpath.get()
+        if not pdbpath or not os.path.exists(pdbpath):
+            self.status['text'] = 'Specified eBook file does not exist'
+            self.sbotton.configure(state='normal')
+            return
+        name = self.name.get()
+        if not name or name == '':
+            self.status['text'] = 'Your forgot to enter the Name on the CC'
+            self.sbotton.configure(state='normal')
+            return
+        ccnum = self.ccnum.get()
+        if not ccnum or ccnum == '':
+            self.status['text'] = 'Your forgot to enter the last 8 digits on the CC'
+            self.sbotton.configure(state='normal')
+            return
+
+        log = 'Command = "python erdr2pml.py --make-pmlz "\n'
+        log += 'PDB Path = "'+ pdbpath + '"\n'
+        log += 'Name = "' + name + '"\n'
+        log += 'Last 8 of CC = "' + ccnum + '"\n'
+        log += '\n\n'
+        log += 'Please Wait ...\n'
+        log = log.encode('utf-8')
+        self.stext.insert(Tkconstants.END,log)
+        self.p2 = self.erdr(pdbpath, name, ccnum)
+
+        # python does not seem to allow you to create
+        # your own eventloop which every other gui does - strange 
+        # so need to use the widget "after" command to force
+        # event loop to run non-gui events every interval
+        self.stext.after(self.interval,self.processPipe)
+        return
+
+
+def main(argv=None):
+    root = Tkinter.Tk()
+    root.title('eReader PDB to PMLZ Conversion')
+    root.resizable(True, False)
+    root.minsize(300, 0)
+    MainDialog(root).pack(fill=Tkconstants.X, expand=1)
+    root.mainloop()
+    return 0
+    
+
+if __name__ == "__main__":
+    sys.exit(main())
index 3e9133a57c98570ec5083d3df1f76fd3ad6c6972..4067ff65530b3f8cfc2b4e8113931ad7933540cf 100644 (file)
@@ -52,8 +52,9 @@
 #  0.11 - fixups for using correct xml for footnotes and sidebars for use with Dropbook
 #  0.12 - Fix added to prevent lowercasing of image names when the pml code itself uses a different case in the link name.
 #  0.13 - change to unbuffered stdout for use with gui front ends
+#  0.14 - contributed enhancement to support --make-pmlz switch
 
-__version__='0.13'
+__version__='0.14'
 
 # Import Psyco if available
 try:
@@ -85,7 +86,7 @@ class Unbuffered:
 import sys
 sys.stdout=Unbuffered(sys.stdout)
 
-import struct, binascii, zlib, os, os.path, urllib
+import struct, binascii, getopt, zlib, os, os.path, urllib, tempfile
 
 try:
     from hashlib import sha1
@@ -592,27 +593,54 @@ def convertEreaderToPml(infile, name, cc, outdir):
     #     file(os.path.join(outdir, 'bookinfo.txt'),'wb').write(bkinfo)
 
 
+def usage():
+    print "Converts DRMed eReader books to PML Source"
+    print "Usage:"
+    print "  erdr2pml [options] infile.pdb [outdir] \"your name\" credit_card_number "
+    print " "
+    print "Options: "
+    print "  -h                prints this message"
+    print "  --make-pmlz       create PMLZ instead of using output directory"
+    print " "
+    print "Note:"
+    print "  if ommitted, outdir defaults based on 'infile.pdb'"
+    print "  It's enough to enter the last 8 digits of the credit card number"
+    return
+
 def main(argv=None):
     global bookname
-    if argv is None:
-        argv = sys.argv
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "h", ["make-pmlz"])
+    except getopt.GetoptError, err:
+        print str(err)
+        usage()
+        return 1
+    make_pmlz = False
+    zipname = None
+    for o, a in opts:
+        if o == "-h":
+            usage()
+            return 0
+        elif o == "--make-pmlz":
+            make_pmlz = True
+            zipname = ''
     
     print "eRdr2Pml v%s. Copyright (c) 2009 The Dark Reverser" % __version__
 
-    if len(argv)!=4 and len(argv)!=5:
-        print "Converts DRMed eReader books to PML Source"
-        print "Usage:"
-        print "  erdr2pml infile.pdb [outdir] \"your name\" credit_card_number "
-        print "Note:"
-        print "  if ommitted, outdir defaults based on 'infile.pdb'"
-        print "  It's enough to enter the last 8 digits of the credit card number"
+    if len(args)!=3 and len(args)!=4:
+        usage()
         return 1
     else:
-        if len(argv)==4:
-            infile, name, cc = argv[1], argv[2], argv[3]
+        if len(args)==3:
+            infile, name, cc = args[0], args[1], args[2]
             outdir = infile[:-4] + '_Source'
-        elif len(argv)==5:
-            infile, outdir, name, cc = argv[1], argv[2], argv[3], argv[4]
+        elif len(args)==4:
+            infile, outdir, name, cc = args[0], args[1], args[2], args[3]
+
+        if make_pmlz :
+            # ignore specified outdir, use tempdir instead
+            outdir = tempfile.mkdtemp()
+                
         bookname = os.path.splitext(os.path.basename(infile))[0]
 
         try:
@@ -620,10 +648,38 @@ def main(argv=None):
             import time
             start_time = time.time()
             convertEreaderToPml(infile, name, cc, outdir)
+
+            if make_pmlz :
+                import zipfile
+                import shutil
+                print "   Creating PMLZ file"
+                zipname = infile[:-4] + '.pmlz'
+                myZipFile = zipfile.ZipFile(zipname,'w',zipfile.ZIP_STORED, False)
+                list = os.listdir(outdir)
+                for file in list:
+                    localname = file
+                    filePath = os.path.join(outdir,file)
+                    if os.path.isfile(filePath):
+                        myZipFile.write(filePath, localname)
+                    elif os.path.isdir(filePath):
+                        imageList = os.listdir(filePath)
+                        localimgdir = os.path.basename(filePath)
+                        for image in imageList:
+                            localname = os.path.join(localimgdir,image)
+                            imagePath = os.path.join(filePath,image)
+                            if os.path.isfile(imagePath):
+                                myZipFile.write(imagePath, localname)
+                myZipFile.close()
+                # remove temporary directory
+                shutil.rmtree(outdir)
+
             end_time = time.time()
             search_time = end_time - start_time
             print 'elapsed time: %.2f seconds' % (search_time, ) 
-            print 'output in %s' % outdir
+            if make_pmlz :
+                print 'output in %s' % zipname
+            else :
+                print 'output in %s' % outdir 
             print "done"
         except ValueError, e:
             print "Error: %s" % e