]> xmof Git - DeDRM.git/commitdiff
tools v3.4
authorApprentice Alf <apprenticealf@gmail.com>
Tue, 8 Feb 2011 17:21:51 +0000 (17:21 +0000)
committerApprentice Alf <apprenticealf@gmail.com>
Thu, 5 Mar 2015 17:22:23 +0000 (17:22 +0000)
29 files changed:
Calibre_Plugins/K4MobiDeDRM_plugin/genbook.py
Calibre_Plugins/Win_OpenSSL_0.9.8o.txt [deleted file]
Calibre_Plugins/ignobleepub_plugin.zip
Calibre_Plugins/ignobleepub_plugin/ignobleepub_plugin.py
Calibre_Plugins/ignobleepub_plugin/zipfix.py
Calibre_Plugins/ineptepub_plugin.zip
Calibre_Plugins/ineptepub_plugin/ineptepub_plugin.py
Calibre_Plugins/ineptepub_plugin/zipfix.py
Calibre_Plugins/ineptpdf_plugin.zip
Calibre_Plugins/ineptpdf_plugin/ineptpdf_plugin.py
Calibre_Plugins/k4mobidedrm_plugin.zip
Calibre_Plugins/k4mobidedrm_plugin/k4mobidedrm_plugin.py
DeDRM_Macintosh_Application/DeDRM.app.txt
DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/genbook.py
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py
DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/zipfix.py
DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/genbook.py
DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/ineptpdf.py
DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mobidedrm.py
DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/zipfix.py
DeDRM_Windows_Application/ReadMe_DeDRM_WinApp.txt
KindleBooks_Tools/KindleBooks/lib/genbook.py
KindleBooks_Tools/KindleBooks/lib/k4mobidedrm.py
Mobi_Additional_Tools/k4mdumpkinfo.py [deleted file]
ePub_Fixer/README_ePub_Fixer.txt
ePub_Fixer/lib/zipfix.py

index a483dec43f454f15c6d1a1123c00c4fb07e34f49..19be51a52388459c164d8d6394c962429876994c 100644 (file)
@@ -192,6 +192,8 @@ class GParser(object):
                 argres[j] = int(argres[j])
         return result
     def getGlyphDim(self, gly):
+        if self.gdpi[gly] == 0:
+            return 0, 0
         maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly]
         maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly]
         return maxh, maxw
@@ -320,6 +322,18 @@ def generateBook(bookDir, raw, fixedimage):
     print 'Processing Meta Data and creating OPF'
     meta_array = getMetaArray(metaFile)
 
+    # replace special chars in title and authors like & < > 
+    title = meta_array['Title']
+    title = title.replace('&','&amp;')
+    title = title.replace('<','&lt;')
+    title = title.replace('>','&gt;')
+    meta_array['Title'] = title
+    authors = meta_array['Authors']
+    authors = authors.replace('&','&amp;')
+    authors = authors.replace('<','&lt;')
+    authors = authors.replace('>','&gt;')
+    meta_array['Authors'] = authors
+
     xname = os.path.join(xmlDir, 'metadata.xml')
     metastr = ''
     for key in meta_array:
diff --git a/Calibre_Plugins/Win_OpenSSL_0.9.8o.txt b/Calibre_Plugins/Win_OpenSSL_0.9.8o.txt
deleted file mode 100644 (file)
index c3ee4fb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-Installing openssl on Windows 64-bit (Windows 2000 and higher)
-
-Win64 OpenSSL v0.9.8o (8Mb)
-http://www.slproweb.com/download/Win64OpenSSL-0_9_8o.exe
-(if you get an error message about missing Visual C++ redistributables... cancel the install and install the below support program from Microsoft, THEN install OpenSSL)
-
-Visual C++ 2008 Redistributables (x64) (1.7Mb)
-http://www.microsoft.com/downloads/details.aspx?familyid=bd2a6171-e2d6-4230-b809-9a8d7548c1b6
-
-
-
-Installing openssl on Windows 32-bit (Windows 2000 and higher)
-
-Win32 OpenSSL v0.9.8o (8Mb)
-http://www.slproweb.com/download/Win32OpenSSL-0_9_8o.exe
-(if you get an error message about missing Visual C++ redistributables... cancel the install and install the below support program from Microsoft, THEN install OpenSSL)
-
-Visual C++ 2008 Redistributables (1.7Mb)
-http://www.microsoft.com/downloads/details.aspx?familyid=9B2DA534-3E03-4391-8A4D-074B9F2BC1BF
-
-
-
-Other versions of OpenSSL (and versions for Windows older than Windows 2000) can be found on the following website.
-
-Shining Light Productions
-http://www.slproweb.com/products/Win32OpenSSL.html
index 8eba53394f6ccefb0487f472a3eccf4f7f376708..3e0bfe1caf6f149542e41d753faa0bfe0be966dc 100644 (file)
Binary files a/Calibre_Plugins/ignobleepub_plugin.zip and b/Calibre_Plugins/ignobleepub_plugin.zip differ
index 50cb51f09af99058cb09ebcdc331149ef6b5918b..04ffc336d686b07d5c4c822fd3345622ffc641c2 100644 (file)
@@ -46,6 +46,8 @@
 #          - Incorporated SomeUpdates zipfix routine.
 #   0.1.2 - bug fix for non-ascii file names in encryption.xml
 #   0.1.3 - Try PyCrypto on Windows first
+#   0.1.4 - update zipfix to deal with mimetype not in correct place
+#   0.1.5 - update zipfix to deal with completely missing mimetype files
 
 """
 Decrypt Barnes & Noble ADEPT encrypted EPUB books.
@@ -271,7 +273,7 @@ class IgnobleDeDRM(FileTypePlugin):
                                 Credit given to I <3 Cabbages for the original stand-alone scripts.'
     supported_platforms     = ['linux', 'osx', 'windows']
     author                  = 'DiapDealer'
-    version                 = (0, 1, 4)
+    version                 = (0, 1, 5)
     minimum_calibre_version = (0, 6, 44)  # Compiled python libraries cannot be imported in earlier versions.
     file_types              = set(['epub'])
     on_import               = True
index 4c862a793fd55b6868874ff85fa39ab38aca2782..a1aafde23e57ee26d332d06ee6bd71dfc53d6ed8 100644 (file)
@@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
 _EXTRA_LEN_OFFSET = 28
 _FILENAME_OFFSET = 30
 _MAX_SIZE = 64 * 1024
+_MIMETYPE = 'application/epub+zip'
+
+class ZipInfo(zipfile.ZipInfo):
+    def __init__(self, *args, **kwargs):
+        if 'compress_type' in kwargs:
+            compress_type = kwargs.pop('compress_type')
+        super(ZipInfo, self).__init__(*args, **kwargs)
+        self.compress_type = compress_type
 
 class fixZip:
     def __init__(self, zinput, zoutput):
+        self.ztype = 'zip'
+        if zinput.lower().find('.epub') >= 0 :
+            self.ztype = 'epub'
         self.inzip = zipfile.ZipFile(zinput,'r')
         self.outzip = zipfile.ZipFile(zoutput,'w')
         # open the input zip for reading only as a raw file
@@ -81,30 +92,15 @@ class fixZip:
         # get the zipinfo for each member of the input archive
         # and copy member over to output archive
         # if problems exist with local vs central filename, fix them
-        # also fix bad epub compression
-        
-        # write mimetype file first, if present, and with no compression
-        for zinfo in self.inzip.infolist():
-            if zinfo.filename == "mimetype":
-                nzinfo = zinfo
-                try: 
-                    data = self.inzip.read(zinfo.filename)
-                except zipfile.BadZipfile or zipfile.error:
-                    local_name = self.getlocalname(zinfo)
-                    data = self.getfiledata(zinfo)
-                    nzinfo.filename = local_name
 
-                nzinfo.date_time = zinfo.date_time
-                nzinfo.compress_type = zipfile.ZIP_STORED
-                nzinfo.flag_bits = 0
-                nzinfo.internal_attr = 0
-                nzinfo.extra = ""
-                self.outzip.writestr(nzinfo,data)
-                break
+        # if epub write mimetype file first, with no compression
+        if self.ztype == 'epub':
+            nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
+            self.outzip.writestr(nzinfo, _MIMETYPE)
 
         # write the rest of the files
         for zinfo in self.inzip.infolist():
-            if zinfo.filename != "mimetype":
+            if zinfo.filename != "mimetype" or self.ztype == '.zip':
                 data = None
                 nzinfo = zinfo
                 try: 
index 6c4d6f62b026bb8a4651e103d8d220e279b2035b..2ce5bce5732527b47f2125871b3b3378bf43c5cf 100644 (file)
Binary files a/Calibre_Plugins/ineptepub_plugin.zip and b/Calibre_Plugins/ineptepub_plugin.zip differ
index e155a3c8b0b44ea4b37188aab5f04497cba4c249..d0541b5844bd0cff2e8fa6ca11f15e0dbe07e265 100644 (file)
@@ -47,7 +47,8 @@
 #           result of Calibre changing to python 2.7.
 #   0.1.3 - bug fix for epubs with non-ascii chars in file names
 #   0.1.4 - default to try PyCrypto first on Windows
-
+#   0.1.5 - update zipfix to handle out of position mimetypes
+#   0.1.6 - update zipfix to handle completely missing mimetype files
 
 """
 Decrypt Adobe ADEPT-encrypted EPUB books.
@@ -371,7 +372,7 @@ class IneptDeDRM(FileTypePlugin):
                                 Credit given to I <3 Cabbages for the original stand-alone scripts.'
     supported_platforms     = ['linux', 'osx', 'windows']
     author                  = 'DiapDealer'
-    version                 = (0, 1, 5)
+    version                 = (0, 1, 6)
     minimum_calibre_version = (0, 6, 44)  # Compiled python libraries cannot be imported in earlier versions.
     file_types              = set(['epub'])
     on_import               = True
index 4c862a793fd55b6868874ff85fa39ab38aca2782..a1aafde23e57ee26d332d06ee6bd71dfc53d6ed8 100644 (file)
@@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
 _EXTRA_LEN_OFFSET = 28
 _FILENAME_OFFSET = 30
 _MAX_SIZE = 64 * 1024
+_MIMETYPE = 'application/epub+zip'
+
+class ZipInfo(zipfile.ZipInfo):
+    def __init__(self, *args, **kwargs):
+        if 'compress_type' in kwargs:
+            compress_type = kwargs.pop('compress_type')
+        super(ZipInfo, self).__init__(*args, **kwargs)
+        self.compress_type = compress_type
 
 class fixZip:
     def __init__(self, zinput, zoutput):
+        self.ztype = 'zip'
+        if zinput.lower().find('.epub') >= 0 :
+            self.ztype = 'epub'
         self.inzip = zipfile.ZipFile(zinput,'r')
         self.outzip = zipfile.ZipFile(zoutput,'w')
         # open the input zip for reading only as a raw file
@@ -81,30 +92,15 @@ class fixZip:
         # get the zipinfo for each member of the input archive
         # and copy member over to output archive
         # if problems exist with local vs central filename, fix them
-        # also fix bad epub compression
-        
-        # write mimetype file first, if present, and with no compression
-        for zinfo in self.inzip.infolist():
-            if zinfo.filename == "mimetype":
-                nzinfo = zinfo
-                try: 
-                    data = self.inzip.read(zinfo.filename)
-                except zipfile.BadZipfile or zipfile.error:
-                    local_name = self.getlocalname(zinfo)
-                    data = self.getfiledata(zinfo)
-                    nzinfo.filename = local_name
 
-                nzinfo.date_time = zinfo.date_time
-                nzinfo.compress_type = zipfile.ZIP_STORED
-                nzinfo.flag_bits = 0
-                nzinfo.internal_attr = 0
-                nzinfo.extra = ""
-                self.outzip.writestr(nzinfo,data)
-                break
+        # if epub write mimetype file first, with no compression
+        if self.ztype == 'epub':
+            nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
+            self.outzip.writestr(nzinfo, _MIMETYPE)
 
         # write the rest of the files
         for zinfo in self.inzip.infolist():
-            if zinfo.filename != "mimetype":
+            if zinfo.filename != "mimetype" or self.ztype == '.zip':
                 data = None
                 nzinfo = zinfo
                 try: 
index d0b8f2aa656eaee865f581d1cd7c91ad0e7b7de2..3174938628833546c32afdfed67b70ad449d8707 100644 (file)
Binary files a/Calibre_Plugins/ineptpdf_plugin.zip and b/Calibre_Plugins/ineptpdf_plugin.zip differ
index d519820d238f8a3f4a38d6a63b7b7f34c52bb2a3..5e3caf3f845f88e81224b1718de05d5c06b75227 100644 (file)
 # ** NOTE ** There is no plugin customization data for the Inept PDF DeDRM plugin.
 #
 # Revision history:
-#   0.1 - Initial release
+#   0.1   - Initial release
+#   0.1.1 - back port ineptpdf 8.4.X support for increased number of encryption methods
+#   0.1.2 - back port ineptpdf 8.4.X bug fixes
+#   0.1.3 - add in fix for improper rejection of session bookkeys with len(bookkey) = length + 1 
 
 """
 Decrypts Adobe ADEPT-encrypted PDF files.
@@ -1544,16 +1547,30 @@ class PDFDocument(object):
         bookkey = bookkey[index:]
         ebx_V = int_value(param.get('V', 4))
         ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
-        # added because of the booktype / decryption book session key error
-        if ebx_V == 3:
-            V = 3        
-        elif ebx_V < 4 or ebx_type < 6:
-            V = ord(bookkey[0])
-            bookkey = bookkey[1:]
+        # added because of improper booktype / decryption book session key errors
+        if length > 0:
+            if len(bookkey) == length:
+                if ebx_V == 3:
+                    V = 3
+                else:
+                    V = 2
+            elif len(bookkey) == length + 1:
+                V = ord(bookkey[0])
+                bookkey = bookkey[1:]
+            else:
+                print "ebx_V is %d  and ebx_type is %d" % (ebx_V, ebx_type)
+                print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
+                print "bookkey[0] is %d" % ord(bookkey[0])
+                raise ADEPTError('error decrypting book session key - mismatched length')
         else:
-            V = 2
-        if length and len(bookkey) != length:
-            raise ADEPTError('error decrypting book session key')
+            # proper length unknown try with whatever you have
+            print "ebx_V is %d  and ebx_type is %d" % (ebx_V, ebx_type)
+            print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
+            print "bookkey[0] is %d" % ord(bookkey[0])
+            if ebx_V == 3:
+                V = 3
+            else:
+                V = 2
         self.decrypt_key = bookkey
         self.genkey = self.genkey_v3 if V == 3 else self.genkey_v2
         self.decipher = self.decrypt_rc4
@@ -2116,7 +2133,7 @@ class IneptPDFDeDRM(FileTypePlugin):
                                 Credit given to I <3 Cabbages for the original stand-alone scripts.'
     supported_platforms     = ['linux', 'osx', 'windows']
     author                  = 'DiapDealer'
-    version                 = (0, 1, 2)
+    version                 = (0, 1, 3)
     minimum_calibre_version = (0, 6, 44)  # Compiled python libraries cannot be imported in earlier versions.
     file_types              = set(['pdf'])
     on_import               = True
index 1efffbbc1eb6b3bf84ed514b2d7f70d3d5964b20..14af1cc742060e9319345a819063fb8b86b51324 100644 (file)
Binary files a/Calibre_Plugins/k4mobidedrm_plugin.zip and b/Calibre_Plugins/k4mobidedrm_plugin.zip differ
index 776ca6e2f0636fc6bf2e1d2e9fe92daea91bc156..6d37a5bc0b25da9145b4a9e54d12834ef77a2474 100644 (file)
@@ -29,7 +29,7 @@ from __future__ import with_statement
 # and import that ZIP into Calibre using its plugin configuration GUI.
 
 
-__version__ = '2.2'
+__version__ = '2.3'
 
 class Unbuffered:
     def __init__(self, stream):
@@ -250,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
                                 Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
         supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
         author              = 'DiapDealer, SomeUpdates' # The author of this plugin
-        version             = (0, 2, 2)   # The version number of this plugin
+        version             = (0, 2, 3)   # The version number of this plugin
         file_types          = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
         on_import           = True # Run this plugin during the import
         priority            = 210  # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
index 865591507355223e12bf1af9e757e82099e3650b..197b27413b9dbbd4e18fe8df9d1a69f6bbdb2320 100644 (file)
Binary files a/DeDRM_Macintosh_Application/DeDRM.app.txt and b/DeDRM_Macintosh_Application/DeDRM.app.txt differ
index dba28391b1431b65e7ee6ffd22403cdc20f23480..1eef22d0e00b131a86f116eea7f323140e356fa0 100644 (file)
@@ -24,7 +24,7 @@
        <key>CFBundleExecutable</key>
        <string>droplet</string>
        <key>CFBundleGetInfoString</key>
-       <string>DeDRM 2.1, Copyright Â© 2010–2011 by Apprentice Alf and others.</string>
+       <string>DeDRM 2.2, Copyright Â© 2010–2011 by Apprentice Alf and others.</string>
        <key>CFBundleIconFile</key>
        <string>droplet</string>
        <key>CFBundleInfoDictionaryVersion</key>
@@ -34,7 +34,7 @@
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleShortVersionString</key>
-       <string>2.1</string>
+       <string>2.2</string>
        <key>CFBundleSignature</key>
        <string>dplt</string>
        <key>LSMinimumSystemVersion</key>
index 16313fe16ec1c26549a7814006037555af799240..80448cabd90996b52fb7dc565b84a3cc982c6cc9 100644 (file)
Binary files a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt and b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt differ
index a483dec43f454f15c6d1a1123c00c4fb07e34f49..19be51a52388459c164d8d6394c962429876994c 100644 (file)
@@ -192,6 +192,8 @@ class GParser(object):
                 argres[j] = int(argres[j])
         return result
     def getGlyphDim(self, gly):
+        if self.gdpi[gly] == 0:
+            return 0, 0
         maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly]
         maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly]
         return maxh, maxw
@@ -320,6 +322,18 @@ def generateBook(bookDir, raw, fixedimage):
     print 'Processing Meta Data and creating OPF'
     meta_array = getMetaArray(metaFile)
 
+    # replace special chars in title and authors like & < > 
+    title = meta_array['Title']
+    title = title.replace('&','&amp;')
+    title = title.replace('<','&lt;')
+    title = title.replace('>','&gt;')
+    meta_array['Title'] = title
+    authors = meta_array['Authors']
+    authors = authors.replace('&','&amp;')
+    authors = authors.replace('<','&lt;')
+    authors = authors.replace('>','&gt;')
+    meta_array['Authors'] = authors
+
     xname = os.path.join(xmlDir, 'metadata.xml')
     metastr = ''
     for key in meta_array:
index ccdd9e4fd6af8c9b3539842cf36d656f9d6382b0..40e97cdec114fe6900ec9dbf03dc32cc2ab4d444 100644 (file)
@@ -1,5 +1,5 @@
 #! /usr/bin/env python
-# ineptpdf.pyw, version 7.7
+# ineptpdf.pyw, version 7.9
 
 from __future__ import with_statement
 
@@ -33,6 +33,7 @@ from __future__ import with_statement
 #   7.6 - backported AES and other fixes from version 8.4.48
 #   7.7 - On Windows try PyCrypto first and OpenSSL next
 #   7.8 - Modify interface to allow use of import
+#   7.9 - Bug fix for some session key errors when len(bookkey) > length required
 
 """
 Decrypts Adobe ADEPT-encrypted PDF files.
@@ -1531,16 +1532,30 @@ class PDFDocument(object):
         bookkey = bookkey[index:]
         ebx_V = int_value(param.get('V', 4))
         ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
-        # added because of the booktype / decryption book session key error
-        if ebx_V == 3:
-            V = 3        
-        elif ebx_V < 4 or ebx_type < 6:
-            V = ord(bookkey[0])
-            bookkey = bookkey[1:]
+        # added because of improper booktype / decryption book session key errors
+        if length > 0:
+            if len(bookkey) == length:
+                if ebx_V == 3:
+                    V = 3        
+                else:
+                    V = 2
+            elif len(bookkey) == length + 1:  
+                V = ord(bookkey[0])
+                bookkey = bookkey[1:]
+            else:
+                print "ebx_V is %d  and ebx_type is %d" % (ebx_V, ebx_type)
+                print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
+                print "bookkey[0] is %d" % ord(bookkey[0])
+                raise ADEPTError('error decrypting book session key - mismatched length')
         else:
-            V = 2
-        if length and len(bookkey) != length:
-            raise ADEPTError('error decrypting book session key')
+            # proper length unknown try with whatever you have
+            print "ebx_V is %d  and ebx_type is %d" % (ebx_V, ebx_type)
+            print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
+            print "bookkey[0] is %d" % ord(bookkey[0])
+            if ebx_V == 3:
+                V = 3        
+            else:
+                V = 2
         self.decrypt_key = bookkey
         self.genkey = self.genkey_v3 if V == 3 else self.genkey_v2
         self.decipher = self.decrypt_rc4
index 776ca6e2f0636fc6bf2e1d2e9fe92daea91bc156..6d37a5bc0b25da9145b4a9e54d12834ef77a2474 100644 (file)
@@ -29,7 +29,7 @@ from __future__ import with_statement
 # and import that ZIP into Calibre using its plugin configuration GUI.
 
 
-__version__ = '2.2'
+__version__ = '2.3'
 
 class Unbuffered:
     def __init__(self, stream):
@@ -250,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
                                 Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
         supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
         author              = 'DiapDealer, SomeUpdates' # The author of this plugin
-        version             = (0, 2, 2)   # The version number of this plugin
+        version             = (0, 2, 3)   # The version number of this plugin
         file_types          = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
         on_import           = True # Run this plugin during the import
         priority            = 210  # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
index 4c862a793fd55b6868874ff85fa39ab38aca2782..a1aafde23e57ee26d332d06ee6bd71dfc53d6ed8 100644 (file)
@@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
 _EXTRA_LEN_OFFSET = 28
 _FILENAME_OFFSET = 30
 _MAX_SIZE = 64 * 1024
+_MIMETYPE = 'application/epub+zip'
+
+class ZipInfo(zipfile.ZipInfo):
+    def __init__(self, *args, **kwargs):
+        if 'compress_type' in kwargs:
+            compress_type = kwargs.pop('compress_type')
+        super(ZipInfo, self).__init__(*args, **kwargs)
+        self.compress_type = compress_type
 
 class fixZip:
     def __init__(self, zinput, zoutput):
+        self.ztype = 'zip'
+        if zinput.lower().find('.epub') >= 0 :
+            self.ztype = 'epub'
         self.inzip = zipfile.ZipFile(zinput,'r')
         self.outzip = zipfile.ZipFile(zoutput,'w')
         # open the input zip for reading only as a raw file
@@ -81,30 +92,15 @@ class fixZip:
         # get the zipinfo for each member of the input archive
         # and copy member over to output archive
         # if problems exist with local vs central filename, fix them
-        # also fix bad epub compression
-        
-        # write mimetype file first, if present, and with no compression
-        for zinfo in self.inzip.infolist():
-            if zinfo.filename == "mimetype":
-                nzinfo = zinfo
-                try: 
-                    data = self.inzip.read(zinfo.filename)
-                except zipfile.BadZipfile or zipfile.error:
-                    local_name = self.getlocalname(zinfo)
-                    data = self.getfiledata(zinfo)
-                    nzinfo.filename = local_name
 
-                nzinfo.date_time = zinfo.date_time
-                nzinfo.compress_type = zipfile.ZIP_STORED
-                nzinfo.flag_bits = 0
-                nzinfo.internal_attr = 0
-                nzinfo.extra = ""
-                self.outzip.writestr(nzinfo,data)
-                break
+        # if epub write mimetype file first, with no compression
+        if self.ztype == 'epub':
+            nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
+            self.outzip.writestr(nzinfo, _MIMETYPE)
 
         # write the rest of the files
         for zinfo in self.inzip.infolist():
-            if zinfo.filename != "mimetype":
+            if zinfo.filename != "mimetype" or self.ztype == '.zip':
                 data = None
                 nzinfo = zinfo
                 try: 
index a483dec43f454f15c6d1a1123c00c4fb07e34f49..19be51a52388459c164d8d6394c962429876994c 100644 (file)
@@ -192,6 +192,8 @@ class GParser(object):
                 argres[j] = int(argres[j])
         return result
     def getGlyphDim(self, gly):
+        if self.gdpi[gly] == 0:
+            return 0, 0
         maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly]
         maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly]
         return maxh, maxw
@@ -320,6 +322,18 @@ def generateBook(bookDir, raw, fixedimage):
     print 'Processing Meta Data and creating OPF'
     meta_array = getMetaArray(metaFile)
 
+    # replace special chars in title and authors like & < > 
+    title = meta_array['Title']
+    title = title.replace('&','&amp;')
+    title = title.replace('<','&lt;')
+    title = title.replace('>','&gt;')
+    meta_array['Title'] = title
+    authors = meta_array['Authors']
+    authors = authors.replace('&','&amp;')
+    authors = authors.replace('<','&lt;')
+    authors = authors.replace('>','&gt;')
+    meta_array['Authors'] = authors
+
     xname = os.path.join(xmlDir, 'metadata.xml')
     metastr = ''
     for key in meta_array:
index ccdd9e4fd6af8c9b3539842cf36d656f9d6382b0..40e97cdec114fe6900ec9dbf03dc32cc2ab4d444 100644 (file)
@@ -1,5 +1,5 @@
 #! /usr/bin/env python
-# ineptpdf.pyw, version 7.7
+# ineptpdf.pyw, version 7.9
 
 from __future__ import with_statement
 
@@ -33,6 +33,7 @@ from __future__ import with_statement
 #   7.6 - backported AES and other fixes from version 8.4.48
 #   7.7 - On Windows try PyCrypto first and OpenSSL next
 #   7.8 - Modify interface to allow use of import
+#   7.9 - Bug fix for some session key errors when len(bookkey) > length required
 
 """
 Decrypts Adobe ADEPT-encrypted PDF files.
@@ -1531,16 +1532,30 @@ class PDFDocument(object):
         bookkey = bookkey[index:]
         ebx_V = int_value(param.get('V', 4))
         ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
-        # added because of the booktype / decryption book session key error
-        if ebx_V == 3:
-            V = 3        
-        elif ebx_V < 4 or ebx_type < 6:
-            V = ord(bookkey[0])
-            bookkey = bookkey[1:]
+        # added because of improper booktype / decryption book session key errors
+        if length > 0:
+            if len(bookkey) == length:
+                if ebx_V == 3:
+                    V = 3        
+                else:
+                    V = 2
+            elif len(bookkey) == length + 1:  
+                V = ord(bookkey[0])
+                bookkey = bookkey[1:]
+            else:
+                print "ebx_V is %d  and ebx_type is %d" % (ebx_V, ebx_type)
+                print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
+                print "bookkey[0] is %d" % ord(bookkey[0])
+                raise ADEPTError('error decrypting book session key - mismatched length')
         else:
-            V = 2
-        if length and len(bookkey) != length:
-            raise ADEPTError('error decrypting book session key')
+            # proper length unknown try with whatever you have
+            print "ebx_V is %d  and ebx_type is %d" % (ebx_V, ebx_type)
+            print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
+            print "bookkey[0] is %d" % ord(bookkey[0])
+            if ebx_V == 3:
+                V = 3        
+            else:
+                V = 2
         self.decrypt_key = bookkey
         self.genkey = self.genkey_v3 if V == 3 else self.genkey_v2
         self.decipher = self.decrypt_rc4
index 776ca6e2f0636fc6bf2e1d2e9fe92daea91bc156..6d37a5bc0b25da9145b4a9e54d12834ef77a2474 100644 (file)
@@ -29,7 +29,7 @@ from __future__ import with_statement
 # and import that ZIP into Calibre using its plugin configuration GUI.
 
 
-__version__ = '2.2'
+__version__ = '2.3'
 
 class Unbuffered:
     def __init__(self, stream):
@@ -250,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
                                 Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
         supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
         author              = 'DiapDealer, SomeUpdates' # The author of this plugin
-        version             = (0, 2, 2)   # The version number of this plugin
+        version             = (0, 2, 3)   # The version number of this plugin
         file_types          = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
         on_import           = True # Run this plugin during the import
         priority            = 210  # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
index 4c862a793fd55b6868874ff85fa39ab38aca2782..a1aafde23e57ee26d332d06ee6bd71dfc53d6ed8 100644 (file)
@@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
 _EXTRA_LEN_OFFSET = 28
 _FILENAME_OFFSET = 30
 _MAX_SIZE = 64 * 1024
+_MIMETYPE = 'application/epub+zip'
+
+class ZipInfo(zipfile.ZipInfo):
+    def __init__(self, *args, **kwargs):
+        if 'compress_type' in kwargs:
+            compress_type = kwargs.pop('compress_type')
+        super(ZipInfo, self).__init__(*args, **kwargs)
+        self.compress_type = compress_type
 
 class fixZip:
     def __init__(self, zinput, zoutput):
+        self.ztype = 'zip'
+        if zinput.lower().find('.epub') >= 0 :
+            self.ztype = 'epub'
         self.inzip = zipfile.ZipFile(zinput,'r')
         self.outzip = zipfile.ZipFile(zoutput,'w')
         # open the input zip for reading only as a raw file
@@ -81,30 +92,15 @@ class fixZip:
         # get the zipinfo for each member of the input archive
         # and copy member over to output archive
         # if problems exist with local vs central filename, fix them
-        # also fix bad epub compression
-        
-        # write mimetype file first, if present, and with no compression
-        for zinfo in self.inzip.infolist():
-            if zinfo.filename == "mimetype":
-                nzinfo = zinfo
-                try: 
-                    data = self.inzip.read(zinfo.filename)
-                except zipfile.BadZipfile or zipfile.error:
-                    local_name = self.getlocalname(zinfo)
-                    data = self.getfiledata(zinfo)
-                    nzinfo.filename = local_name
 
-                nzinfo.date_time = zinfo.date_time
-                nzinfo.compress_type = zipfile.ZIP_STORED
-                nzinfo.flag_bits = 0
-                nzinfo.internal_attr = 0
-                nzinfo.extra = ""
-                self.outzip.writestr(nzinfo,data)
-                break
+        # if epub write mimetype file first, with no compression
+        if self.ztype == 'epub':
+            nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
+            self.outzip.writestr(nzinfo, _MIMETYPE)
 
         # write the rest of the files
         for zinfo in self.inzip.infolist():
-            if zinfo.filename != "mimetype":
+            if zinfo.filename != "mimetype" or self.ztype == '.zip':
                 data = None
                 nzinfo = zinfo
                 try: 
index 73c13b0fed724566432c944a92cde99ad35d6459..8e1cfea5b321dc5a3782e88a0a953e1bd93c1a43 100644 (file)
@@ -1,5 +1,5 @@
-ReadMe_DeDRM_WinApp_v1.3
-------------------------
+ReadMe_DeDRM_WinApp_v1.2
+-----------------------
 
 DeDRM_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto theDeDRM_Drop_Target to have the DRM removed.  It repackages the"tools" python software in one easy to use program.
 
index a483dec43f454f15c6d1a1123c00c4fb07e34f49..19be51a52388459c164d8d6394c962429876994c 100644 (file)
@@ -192,6 +192,8 @@ class GParser(object):
                 argres[j] = int(argres[j])
         return result
     def getGlyphDim(self, gly):
+        if self.gdpi[gly] == 0:
+            return 0, 0
         maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly]
         maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly]
         return maxh, maxw
@@ -320,6 +322,18 @@ def generateBook(bookDir, raw, fixedimage):
     print 'Processing Meta Data and creating OPF'
     meta_array = getMetaArray(metaFile)
 
+    # replace special chars in title and authors like & < > 
+    title = meta_array['Title']
+    title = title.replace('&','&amp;')
+    title = title.replace('<','&lt;')
+    title = title.replace('>','&gt;')
+    meta_array['Title'] = title
+    authors = meta_array['Authors']
+    authors = authors.replace('&','&amp;')
+    authors = authors.replace('<','&lt;')
+    authors = authors.replace('>','&gt;')
+    meta_array['Authors'] = authors
+
     xname = os.path.join(xmlDir, 'metadata.xml')
     metastr = ''
     for key in meta_array:
index 776ca6e2f0636fc6bf2e1d2e9fe92daea91bc156..6d37a5bc0b25da9145b4a9e54d12834ef77a2474 100644 (file)
@@ -29,7 +29,7 @@ from __future__ import with_statement
 # and import that ZIP into Calibre using its plugin configuration GUI.
 
 
-__version__ = '2.2'
+__version__ = '2.3'
 
 class Unbuffered:
     def __init__(self, stream):
@@ -250,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
                                 Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
         supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
         author              = 'DiapDealer, SomeUpdates' # The author of this plugin
-        version             = (0, 2, 2)   # The version number of this plugin
+        version             = (0, 2, 3)   # The version number of this plugin
         file_types          = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
         on_import           = True # Run this plugin during the import
         priority            = 210  # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
diff --git a/Mobi_Additional_Tools/k4mdumpkinfo.py b/Mobi_Additional_Tools/k4mdumpkinfo.py
deleted file mode 100644 (file)
index e7e119d..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-# engine to remove drm from Kindle for Mac books
-# for personal use for archiving and converting your ebooks
-#  PLEASE DO NOT PIRATE! 
-# We want all authors and Publishers, and eBook stores to live long and prosperous lives
-#
-# it borrows heavily from works by CMBDTC, IHeartCabbages, skindle, 
-#    unswindle, DiapDealer, some_updates and many many others
-
-from __future__ import with_statement
-
-class Unbuffered:
-    def __init__(self, stream):
-        self.stream = stream
-    def write(self, data):
-        self.stream.write(data)
-        self.stream.flush()
-    def __getattr__(self, attr):
-        return getattr(self.stream, attr)
-
-import sys
-sys.stdout=Unbuffered(sys.stdout)
-import os, csv, getopt
-from struct import pack
-from struct import unpack
-import zlib
-
-# for handling sub processes
-import subprocess
-from subprocess import Popen, PIPE, STDOUT
-
-#Exception Handling
-class K4MDEDRMError(Exception):
-    pass
-class K4MDEDRMFatal(Exception):
-    pass
-
-#
-# crypto routines
-#
-import hashlib
-
-def MD5(message):
-    ctx = hashlib.md5()
-    ctx.update(message)
-    return ctx.digest()
-
-def SHA1(message):
-    ctx = hashlib.sha1()
-    ctx.update(message)
-    return ctx.digest()
-
-def SHA256(message):
-    ctx = hashlib.sha256()
-    ctx.update(message)
-    return ctx.digest()
-
-# interface to needed routines in openssl's libcrypto
-def _load_crypto_libcrypto():
-    from ctypes import CDLL, byref, POINTER, c_void_p, c_char_p, c_int, c_long, \
-        Structure, c_ulong, create_string_buffer, addressof, string_at, cast
-    from ctypes.util import find_library
-
-    libcrypto = find_library('crypto')
-    if libcrypto is None:
-        raise K4MDEDRMError('libcrypto not found')
-    libcrypto = CDLL(libcrypto)
-
-    AES_MAXNR = 14
-    c_char_pp = POINTER(c_char_p)
-    c_int_p = POINTER(c_int)
-
-    class AES_KEY(Structure):
-        _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), ('rounds', c_int)]
-    AES_KEY_p = POINTER(AES_KEY)
-    
-    def F(restype, name, argtypes):
-        func = getattr(libcrypto, name)
-        func.restype = restype
-        func.argtypes = argtypes
-        return func
-    
-    AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,c_int])
-
-    AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',[c_char_p, c_int, AES_KEY_p])
-
-    PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1', 
-                                [c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p])
-    
-    class LibCrypto(object):
-        def __init__(self):
-            self._blocksize = 0
-            self._keyctx = None
-            self.iv = 0
-        def set_decrypt_key(self, userkey, iv):
-            self._blocksize = len(userkey)
-            if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) :
-                raise K4MDEDRMError('AES improper key used')
-                return
-            keyctx = self._keyctx = AES_KEY()
-            self.iv = iv
-            rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx)
-            if rv < 0:
-                raise K4MDEDRMError('Failed to initialize AES key')
-        def decrypt(self, data):
-            out = create_string_buffer(len(data))
-            rv = AES_cbc_encrypt(data, out, len(data), self._keyctx, self.iv, 0)
-            if rv == 0:
-                raise K4MDEDRMError('AES decryption failed')
-            return out.raw
-        def keyivgen(self, passwd):
-            salt = '16743'
-            saltlen = 5
-            passlen = len(passwd)
-            iter = 0x3e8
-            keylen = 80
-            out = create_string_buffer(keylen)
-            rv = PKCS5_PBKDF2_HMAC_SHA1(passwd, passlen, salt, saltlen, iter, keylen, out)
-            return out.raw
-    return LibCrypto
-
-def _load_crypto():
-    LibCrypto = None
-    try:
-        LibCrypto = _load_crypto_libcrypto()
-    except (ImportError, K4MDEDRMError):
-        pass
-    return LibCrypto
-
-LibCrypto = _load_crypto()
-
-#
-# Utility Routines
-#
-
-# uses a sub process to get the Hard Drive Serial Number using ioreg
-# returns with the first found serial number in that class
-def GetVolumeSerialNumber():
-    sernum = os.getenv('MYSERIALNUMBER')
-    if sernum != None:
-        return sernum
-    cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver'
-    cmdline = cmdline.encode(sys.getfilesystemencoding())
-    p = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
-    poll = p.wait('wait')
-    results = p.read()
-    reslst = results.split('\n')
-    cnt = len(reslst)
-    bsdname = None
-    sernum = None
-    foundIt = False
-    for j in xrange(cnt):
-        resline = reslst[j]
-        pp = resline.find('"Serial Number" = "')
-        if pp >= 0:
-            sernum = resline[pp+19:-1]
-            sernum = sernum.strip()
-        bb = resline.find('"BSD Name" = "')
-        if bb >= 0:
-            bsdname = resline[bb+14:-1]
-            bsdname = bsdname.strip()
-            if (bsdname == 'disk0') and (sernum != None):
-                foundIt = True
-                break
-    if not foundIt:
-        sernum = '9999999999'
-    return sernum
-
-# uses unix env to get username instead of using sysctlbyname 
-def GetUserName():
-    username = os.getenv('USER')
-    return username
-
-MAX_PATH = 255
-
-#
-# start of Kindle specific routines
-#
-
-global kindleDatabase
-
-# Various character maps used to decrypt books. Probably supposed to act as obfuscation
-charMap1 = "n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M"
-charMap2 = "ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM" 
-charMap3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
-charMap4 = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"
-
-# Encode the bytes in data with the characters in map
-def encode(data, map):
-    result = ""
-    for char in data:
-        value = ord(char)
-        Q = (value ^ 0x80) // len(map)
-        R = value % len(map)
-        result += map[Q]
-        result += map[R]
-    return result
-  
-# Hash the bytes in data and then encode the digest with the characters in map
-def encodeHash(data,map):
-    return encode(MD5(data),map)
-
-# Decode the string in data with the characters in map. Returns the decoded bytes
-def decode(data,map):
-    result = ""
-    for i in range (0,len(data)-1,2):
-        high = map.find(data[i])
-        low = map.find(data[i+1])
-        if (high == -1) or (low == -1) :
-            break
-        value = (((high * len(map)) ^ 0x80) & 0xFF) + low
-        result += pack("B",value)
-    return result
-
-# implements an Pseudo Mac Version of Windows built-in Crypto routine
-def CryptUnprotectData(encryptedData):
-    sp = GetVolumeSerialNumber() + '!@#' + GetUserName()
-    passwdData = encode(SHA256(sp),charMap1)
-    crp = LibCrypto()
-    key_iv = crp.keyivgen(passwdData)
-    key = key_iv[0:32]
-    iv = key_iv[32:48]
-    crp.set_decrypt_key(key,iv)
-    cleartext = crp.decrypt(encryptedData)
-    return cleartext
-
-# Locate and open the .kindle-info file
-def openKindleInfo():
-    home = os.getenv('HOME')
-    kinfopath = home +  '/Library/Application Support/Amazon/Kindle/storage/.kindle-info'
-    if not os.path.exists(kinfopath):
-        kinfopath = home +  '/Library/Application Support/Amazon/Kindle for Mac/storage/.kindle-info'
-        if not os.path.exists(kinfopath):
-            raise K4MDEDRMError('Error: .kindle-info file can not be found')
-    return open(kinfopath,'r')
-
-# Parse the Kindle.info file and return the records as a list of key-values
-def parseKindleInfo():
-    DB = {}
-    infoReader = openKindleInfo()
-    infoReader.read(1)
-    data = infoReader.read()
-    items = data.split('[')
-    for item in items:
-        splito = item.split(':')
-        DB[splito[0]] =splito[1]
-    return DB
-
-# Get a record from the Kindle.info file for the key "hashedKey" (already hashed and encoded). Return the decoded and decrypted record
-def getKindleInfoValueForHash(hashedKey):
-    global kindleDatabase
-    encryptedValue = decode(kindleDatabase[hashedKey],charMap2)
-    cleartext = CryptUnprotectData(encryptedValue)
-    return decode(cleartext, charMap1)
-#  Get a record from the Kindle.info file for the string in "key" (plaintext). Return the decoded and decrypted record
-def getKindleInfoValueForKey(key):
-    return getKindleInfoValueForHash(encodeHash(key,charMap2))
-
-# Find if the original string for a hashed/encoded string is known. If so return the original string othwise return an empty string.
-def findNameForHash(hash):
-    names = ["kindle.account.tokens","kindle.cookie.item","eulaVersionAccepted","login_date","kindle.token.item","login","kindle.key.item","kindle.name.info","kindle.device.info", "MazamaRandomNumber"]
-    result = ""
-    for name in names:
-        if hash == encodeHash(name, charMap2):
-           result = name
-           break
-    return result
-    
-# Print all the records from the kindle.info file (option -i)
-def printKindleInfo():
-    for record in kindleDatabase:
-        name = findNameForHash(record)
-        if name != "" :
-            print (name)
-            print ("--------------------------")
-        else :
-            print ("Unknown Record")
-        print getKindleInfoValueForHash(record)
-        print "\n"
-
-#
-# PID generation routines
-#
-  
-# Returns two bit at offset from a bit field
-def getTwoBitsFromBitField(bitField,offset):
-    byteNumber = offset // 4
-    bitPosition = 6 - 2*(offset % 4)
-    return ord(bitField[byteNumber]) >> bitPosition & 3
-
-# Returns the six bits at offset from a bit field
-def getSixBitsFromBitField(bitField,offset):
-     offset *= 3
-     value = (getTwoBitsFromBitField(bitField,offset) <<4) + (getTwoBitsFromBitField(bitField,offset+1) << 2) +getTwoBitsFromBitField(bitField,offset+2)
-     return value
-     
-# 8 bits to six bits encoding from hash to generate PID string
-def encodePID(hash):
-    global charMap3
-    PID = ""
-    for position in range (0,8):
-        PID += charMap3[getSixBitsFromBitField(hash,position)]
-    return PID
-    
-#
-# Main
-#   
-
-def main(argv=sys.argv):
-    global kindleDatabase
-    
-    kindleDatabase = None
-
-    #
-    # Read the encrypted database
-    #
-    
-    try:
-        kindleDatabase = parseKindleInfo()
-    except Exception, message:
-        print(message)
-    
-    if kindleDatabase != None :
-        printKindleInfo()
-     
-    return 0
-
-import signal
-import threading
-import subprocess
-from subprocess import Popen, PIPE, STDOUT
-
-# **heavily** chopped up and modfied version of asyncproc.py
-# to make it actually work on Windows as well as Mac/Linux
-# For the original see:
-# "http://www.lysator.liu.se/~bellman/download/"
-# author is  "Thomas Bellman <bellman@lysator.liu.se>"
-# available under GPL version 3 or Later
-
-# create an asynchronous subprocess whose output can be collected in
-# a non-blocking manner
-
-# What a mess!  Have to use threads just to get non-blocking io
-# in a cross-platform manner
-
-# luckily all thread use is hidden within this class
-
-class Process(object):
-    def __init__(self, *params, **kwparams):
-        if len(params) <= 3:
-            kwparams.setdefault('stdin', subprocess.PIPE)
-        if len(params) <= 4:
-            kwparams.setdefault('stdout', subprocess.PIPE)
-        if len(params) <= 5:
-            kwparams.setdefault('stderr', subprocess.PIPE)
-        self.__pending_input = []
-        self.__collected_outdata = []
-        self.__collected_errdata = []
-        self.__exitstatus = None
-        self.__lock = threading.Lock()
-        self.__inputsem = threading.Semaphore(0)
-        self.__quit = False
-
-        self.__process = subprocess.Popen(*params, **kwparams)
-
-        if self.__process.stdin:
-            self.__stdin_thread = threading.Thread(
-                name="stdin-thread",
-                target=self.__feeder, args=(self.__pending_input,
-                                            self.__process.stdin))
-            self.__stdin_thread.setDaemon(True)
-            self.__stdin_thread.start()
-
-        if self.__process.stdout:
-            self.__stdout_thread = threading.Thread(
-                name="stdout-thread",
-                target=self.__reader, args=(self.__collected_outdata,
-                                           self.__process.stdout))
-            self.__stdout_thread.setDaemon(True)
-            self.__stdout_thread.start()
-
-        if self.__process.stderr:
-            self.__stderr_thread = threading.Thread(
-                name="stderr-thread",
-                target=self.__reader, args=(self.__collected_errdata,
-                                           self.__process.stderr))
-            self.__stderr_thread.setDaemon(True)
-            self.__stderr_thread.start()
-
-    def pid(self):
-        return self.__process.pid
-
-    def kill(self, signal):
-        self.__process.send_signal(signal)
-
-    # check on subprocess (pass in 'nowait') to act like poll
-    def wait(self, flag):
-        if flag.lower() == 'nowait':
-            rc = self.__process.poll()
-        else:
-            rc = self.__process.wait()
-        if rc != None:
-            if self.__process.stdin:
-                self.closeinput()
-            if self.__process.stdout:
-                self.__stdout_thread.join()
-            if self.__process.stderr:
-                self.__stderr_thread.join()
-        return self.__process.returncode
-
-    def terminate(self):
-        if self.__process.stdin:
-            self.closeinput()
-        self.__process.terminate()
-
-    # thread gets data from subprocess stdout
-    def __reader(self, collector, source):
-        while True:
-            data = os.read(source.fileno(), 65536)
-            self.__lock.acquire()
-            collector.append(data)
-            self.__lock.release()
-            if data == "":
-                source.close()
-                break
-        return
-
-    # thread feeds data to subprocess stdin
-    def __feeder(self, pending, drain):
-        while True:
-            self.__inputsem.acquire()
-            self.__lock.acquire()
-            if not pending  and self.__quit:
-                drain.close()
-                self.__lock.release()
-                break
-            data = pending.pop(0)
-            self.__lock.release()
-            drain.write(data)
-
-    # non-blocking read of data from subprocess stdout
-    def read(self):
-        self.__lock.acquire()
-        outdata = "".join(self.__collected_outdata)
-        del self.__collected_outdata[:]
-        self.__lock.release()
-        return outdata
-
-    # non-blocking read of data from subprocess stderr
-    def readerr(self):
-        self.__lock.acquire()
-        errdata = "".join(self.__collected_errdata)
-        del self.__collected_errdata[:]
-        self.__lock.release()
-        return errdata
-
-    # non-blocking write to stdin of subprocess
-    def write(self, data):
-        if self.__process.stdin is None:
-            raise ValueError("Writing to process with stdin not a pipe")
-        self.__lock.acquire()
-        self.__pending_input.append(data)
-        self.__inputsem.release()
-        self.__lock.release()
-
-    # close stdinput of subprocess
-    def closeinput(self):
-        self.__lock.acquire()
-        self.__quit = True
-        self.__inputsem.release()
-        self.__lock.release()
-
-
-if __name__ == '__main__':
-    sys.exit(main())
index fb71e9da8dfd90241033b8b22ef782cdfde8e1b0..b864d0749fa0816fa712ef12cf9be24560d470ef 100644 (file)
@@ -1,8 +1,8 @@
 ePub_Fixer
 
-ePubs are specially crafted zip archives whose first file is an uncompresssed "mimetype" file.  Unfortunately, many of the DRM encoded Adobe Adept and Barnes & Noble ePubs are not "proper" zip archives in that the names of some files in the zip central directory do NOT match the local name given in archive itself, or they do not have an uncompressed mimetype file as the first file in the archive.  These types of epubs are technically incorrect/corrupted and can not be read by many other programs.
+ePubs are specially crafted zip archives.  Unfortunately, many of the DRM encoded Adobe Adept and Barnes & Noble ePubs are not "proper" zip archives in that the names of some files in the zip central directory do NOT match the local name given in archive itself.  This type of zip archive is technically incorrect/corrupted and can not be read by many other programs.
 
-ePub_Fixer was designed to fix improperly created zip archives of these types.
+ePub_Fixer was designed to fix improperly created zip archives of this type.
 
 1. Simply double-click to launch ePub_Fixer.pyw.
 
index 4c862a793fd55b6868874ff85fa39ab38aca2782..a1aafde23e57ee26d332d06ee6bd71dfc53d6ed8 100644 (file)
@@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
 _EXTRA_LEN_OFFSET = 28
 _FILENAME_OFFSET = 30
 _MAX_SIZE = 64 * 1024
+_MIMETYPE = 'application/epub+zip'
+
+class ZipInfo(zipfile.ZipInfo):
+    def __init__(self, *args, **kwargs):
+        if 'compress_type' in kwargs:
+            compress_type = kwargs.pop('compress_type')
+        super(ZipInfo, self).__init__(*args, **kwargs)
+        self.compress_type = compress_type
 
 class fixZip:
     def __init__(self, zinput, zoutput):
+        self.ztype = 'zip'
+        if zinput.lower().find('.epub') >= 0 :
+            self.ztype = 'epub'
         self.inzip = zipfile.ZipFile(zinput,'r')
         self.outzip = zipfile.ZipFile(zoutput,'w')
         # open the input zip for reading only as a raw file
@@ -81,30 +92,15 @@ class fixZip:
         # get the zipinfo for each member of the input archive
         # and copy member over to output archive
         # if problems exist with local vs central filename, fix them
-        # also fix bad epub compression
-        
-        # write mimetype file first, if present, and with no compression
-        for zinfo in self.inzip.infolist():
-            if zinfo.filename == "mimetype":
-                nzinfo = zinfo
-                try: 
-                    data = self.inzip.read(zinfo.filename)
-                except zipfile.BadZipfile or zipfile.error:
-                    local_name = self.getlocalname(zinfo)
-                    data = self.getfiledata(zinfo)
-                    nzinfo.filename = local_name
 
-                nzinfo.date_time = zinfo.date_time
-                nzinfo.compress_type = zipfile.ZIP_STORED
-                nzinfo.flag_bits = 0
-                nzinfo.internal_attr = 0
-                nzinfo.extra = ""
-                self.outzip.writestr(nzinfo,data)
-                break
+        # if epub write mimetype file first, with no compression
+        if self.ztype == 'epub':
+            nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
+            self.outzip.writestr(nzinfo, _MIMETYPE)
 
         # write the rest of the files
         for zinfo in self.inzip.infolist():
-            if zinfo.filename != "mimetype":
+            if zinfo.filename != "mimetype" or self.ztype == '.zip':
                 data = None
                 nzinfo = zinfo
                 try: