]> xmof Git - DeDRM.git/commitdiff
tools v1.8
authorApprentice Alf <apprenticealf@gmail.com>
Sat, 24 Jul 2010 11:55:24 +0000 (12:55 +0100)
committerApprentice Alf <apprenticealf@gmail.com>
Tue, 3 Mar 2015 07:19:44 +0000 (07:19 +0000)
18 files changed:
Adobe_EPUB_Tools/ineptepub.pyw
Adobe_EPUB_Tools/ineptkey.pyw
Adobe_EPUB_Tools/ineptkeymac.pyw [deleted file]
Kindle_Mobi_Tools/LZskindle4PCv1_1/EZskindle4PCv1_1_1.cpp [new file with mode: 0644]
Kindle_Mobi_Tools/LZskindle4PCv1_1/EZskindle4PCv1_1_1.exe [new file with mode: 0644]
Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle Read Me.txt [new file with mode: 0644]
Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle4PCv1_1.cpp [new file with mode: 0644]
Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle4PCv1_1.exe [new file with mode: 0644]
Kindle_Mobi_Tools/LZskindle4PCv1_1/ReadMe.txt [new file with mode: 0644]
Kindle_Mobi_Tools/MobiDeDRM.pyw
Kindle_Mobi_Tools/lib/kindlepid.py
Kindle_Mobi_Tools/lib/mobidedrm.py
Kindle_Mobi_Tools/unswindle/mobidedrm.py
Kindle_Mobi_Tools/unswindle/unswindle.pyw
Macintosh_Applications/Mobipocket Unlocker.app/Contents/Resources/MobiDeDRM.py
Topaz_Tools/TopazExtract_Kindle4PC.pyw
Topaz_Tools/TopazExtract_KindleV1_iPhone_iPad.pyw [new file with mode: 0644]
Topaz_Tools/lib/convert2xml.py

index 35e18afaefe2d6f09a4803cb1a586a63bf2243be..d6c5f7d269fb58d8cc8c868f616ecab8fb9ab5dc 100644 (file)
@@ -1,18 +1,29 @@
 #! /usr/bin/python
+# -*- coding: utf-8 -*-
 
-# ineptepub.pyw, version 4.1
+# ineptepub.pyw, version 5.2
+# Copyright © 2009-2010 i♥cabbages
 
-# To run this program install Python 2.6 from http://www.python.org/download/
-# and PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto
-# (make sure to install the version for Python 2.6).  Save this script file as
-# ineptepub.pyw and double-click on it to run it.
+# Released under the terms of the GNU General Public Licence, version 3 or
+# later.  <http://www.gnu.org/licenses/>
+
+# Windows users: Before running this program, you must first install Python 2.6
+#   from <http://www.python.org/download/> and PyCrypto from
+#   <http://www.voidspace.org.uk/python/modules.shtml#pycrypto> (make sure to
+#   install the version for Python 2.6).  Save this script file as
+#   ineptepub.pyw and double-click on it to run it.
+#
+# Mac OS X users: Save this script file as ineptepub.pyw.  You can run this
+#   program from the command line (pythonw ineptepub.pyw) or by double-clicking
+#   it when it has been associated with PythonLauncher.
 
 # Revision history:
 #   1 - Initial release
 #   2 - Rename to INEPT, fix exit code
-#   3 - Add cmd or gui choosing
-#   4 - support for 1.7.2 support (anon)
-#   4.1 - backward compatibility for 1.7.1 and old adeptkey.der
+#   5 - Version bump to avoid (?) confusion;
+#       Improve OS X support by using OpenSSL when available
+#   5.1 - Improve OpenSSL error checking
+#   5.2 - Fix ctypes error causing segfaults on some systems
 
 """
 Decrypt Adobe ADEPT-encrypted EPUB books.
@@ -34,116 +45,223 @@ import Tkconstants
 import tkFileDialog
 import tkMessageBox
 
-try:
-    from Crypto.Cipher import AES
-    from Crypto.PublicKey import RSA
-except ImportError:
-    AES = None
-    RSA = None
-
-META_NAMES = ('mimetype', 'META-INF/rights.xml', 'META-INF/encryption.xml')
-NSMAP = {'adept': 'http://ns.adobe.com/adept',
-         'enc': 'http://www.w3.org/2001/04/xmlenc#'}
-
+class ADEPTError(Exception):
+    pass
 
-# ASN.1 parsing code from tlslite
+def _load_crypto_libcrypto():
+    from ctypes import CDLL, POINTER, c_void_p, c_char_p, c_int, c_long, \
+        Structure, c_ulong, create_string_buffer, cast
+    from ctypes.util import find_library
 
-def bytesToNumber(bytes):
-    total = 0L
-    multiplier = 1L
-    for count in range(len(bytes)-1, -1, -1):
-        byte = bytes[count]
-        total += multiplier * byte
-        multiplier *= 256
-    return total
+    libcrypto = find_library('crypto')
+    if libcrypto is None:
+        raise ADEPTError('libcrypto not found')
+    libcrypto = CDLL(libcrypto)
 
-class ASN1Error(Exception):
-    pass
+    RSA_NO_PADDING = 3
+    AES_MAXNR = 14
+    
+    c_char_pp = POINTER(c_char_p)
+    c_int_p = POINTER(c_int)
 
-class ASN1Parser(object):
-    class Parser(object):
-        def __init__(self, bytes):
-            self.bytes = bytes
-            self.index = 0
+    class RSA(Structure):
+        pass
+    RSA_p = POINTER(RSA)
     
-        def get(self, length):
-            if self.index + length > len(self.bytes):
-                raise ASN1Error("Error decoding ASN.1")
-            x = 0
-            for count in range(length):
-                x <<= 8
-                x |= self.bytes[self.index]
-                self.index += 1
-            return x
+    class AES_KEY(Structure):
+        _fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))),
+                    ('rounds', c_int)]
+    AES_KEY_p = POINTER(AES_KEY)
     
-        def getFixBytes(self, lengthBytes):
-            bytes = self.bytes[self.index : self.index+lengthBytes]
-            self.index += lengthBytes
-            return bytes
+    def F(restype, name, argtypes):
+        func = getattr(libcrypto, name)
+        func.restype = restype
+        func.argtypes = argtypes
+        return func
     
-        def getVarBytes(self, lengthLength):
-            lengthBytes = self.get(lengthLength)
-            return self.getFixBytes(lengthBytes)
+    d2i_RSAPrivateKey = F(RSA_p, 'd2i_RSAPrivateKey',
+                          [RSA_p, c_char_pp, c_long])
+    RSA_size = F(c_int, 'RSA_size', [RSA_p])
+    RSA_private_decrypt = F(c_int, 'RSA_private_decrypt',
+                            [c_int, c_char_p, c_char_p, RSA_p, c_int])
+    RSA_free = F(None, 'RSA_free', [RSA_p])
+    AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',
+                            [c_char_p, c_int, AES_KEY_p])
+    AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',
+                        [c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,
+                         c_int])
     
-        def getFixList(self, length, lengthList):
-            l = [0] * lengthList
-            for x in range(lengthList):
-                l[x] = self.get(length)
-            return l
+    class RSA(object):
+        def __init__(self, der):
+            buf = create_string_buffer(der)
+            pp = c_char_pp(cast(buf, c_char_p))
+            rsa = self._rsa = d2i_RSAPrivateKey(None, pp, len(der))
+            if rsa is None:
+                raise ADEPTError('Error parsing ADEPT user key DER')
+        
+        def decrypt(self, from_):
+            rsa = self._rsa
+            to = create_string_buffer(RSA_size(rsa))
+            dlen = RSA_private_decrypt(len(from_), from_, to, rsa,
+                                       RSA_NO_PADDING)
+            if dlen < 0:
+                raise ADEPTError('RSA decryption failed')
+            return to[:dlen]
     
-        def getVarList(self, length, lengthLength):
-            lengthList = self.get(lengthLength)
-            if lengthList % length != 0:
-                raise ASN1Error("Error decoding ASN.1")
-            lengthList = int(lengthList/length)
-            l = [0] * lengthList
-            for x in range(lengthList):
-                l[x] = self.get(length)
-            return l
+        def __del__(self):
+            if self._rsa is not None:
+                RSA_free(self._rsa)
+                self._rsa = None
+
+    class AES(object):
+        def __init__(self, userkey):
+            self._blocksize = len(userkey)
+            key = self._key = AES_KEY()
+            rv = AES_set_decrypt_key(userkey, len(userkey) * 8, key)
+            if rv < 0:
+                raise ADEPTError('Failed to initialize AES key')
     
-        def startLengthCheck(self, lengthLength):
-            self.lengthCheck = self.get(lengthLength)
-            self.indexCheck = self.index
+        def decrypt(self, data):
+            out = create_string_buffer(len(data))
+            iv = ("\x00" * self._blocksize)
+            rv = AES_cbc_encrypt(data, out, len(data), self._key, iv, 0)
+            if rv == 0:
+                raise ADEPTError('AES decryption failed')
+            return out.raw
+
+    return (AES, RSA)
+
+def _load_crypto_pycrypto():
+    from Crypto.Cipher import AES as _AES
+    from Crypto.PublicKey import RSA as _RSA
+
+    # ASN.1 parsing code from tlslite
+    class ASN1Error(Exception):
+        pass
     
-        def setLengthCheck(self, length):
-            self.lengthCheck = length
-            self.indexCheck = self.index
+    class ASN1Parser(object):
+        class Parser(object):
+            def __init__(self, bytes):
+                self.bytes = bytes
+                self.index = 0
     
-        def stopLengthCheck(self):
-            if (self.index - self.indexCheck) != self.lengthCheck:
-                raise ASN1Error("Error decoding ASN.1")
+            def get(self, length):
+                if self.index + length > len(self.bytes):
+                    raise ASN1Error("Error decoding ASN.1")
+                x = 0
+                for count in range(length):
+                    x <<= 8
+                    x |= self.bytes[self.index]
+                    self.index += 1
+                return x
     
-        def atLengthCheck(self):
-            if (self.index - self.indexCheck) < self.lengthCheck:
-                return False
-            elif (self.index - self.indexCheck) == self.lengthCheck:
-                return True
-            else:
-                raise ASN1Error("Error decoding ASN.1")
-
-    def __init__(self, bytes):
-        p = self.Parser(bytes)
-        p.get(1)
-        self.length = self._getASN1Length(p)
-        self.value = p.getFixBytes(self.length)
-
-    def getChild(self, which):
-        p = self.Parser(self.value)
-        for x in range(which+1):
-            markIndex = p.index
+            def getFixBytes(self, lengthBytes):
+                bytes = self.bytes[self.index : self.index+lengthBytes]
+                self.index += lengthBytes
+                return bytes
+    
+            def getVarBytes(self, lengthLength):
+                lengthBytes = self.get(lengthLength)
+                return self.getFixBytes(lengthBytes)
+    
+            def getFixList(self, length, lengthList):
+                l = [0] * lengthList
+                for x in range(lengthList):
+                    l[x] = self.get(length)
+                return l
+    
+            def getVarList(self, length, lengthLength):
+                lengthList = self.get(lengthLength)
+                if lengthList % length != 0:
+                    raise ASN1Error("Error decoding ASN.1")
+                lengthList = int(lengthList/length)
+                l = [0] * lengthList
+                for x in range(lengthList):
+                    l[x] = self.get(length)
+                return l
+    
+            def startLengthCheck(self, lengthLength):
+                self.lengthCheck = self.get(lengthLength)
+                self.indexCheck = self.index
+    
+            def setLengthCheck(self, length):
+                self.lengthCheck = length
+                self.indexCheck = self.index
+    
+            def stopLengthCheck(self):
+                if (self.index - self.indexCheck) != self.lengthCheck:
+                    raise ASN1Error("Error decoding ASN.1")
+    
+            def atLengthCheck(self):
+                if (self.index - self.indexCheck) < self.lengthCheck:
+                    return False
+                elif (self.index - self.indexCheck) == self.lengthCheck:
+                    return True
+                else:
+                    raise ASN1Error("Error decoding ASN.1")
+    
+        def __init__(self, bytes):
+            p = self.Parser(bytes)
             p.get(1)
-            length = self._getASN1Length(p)
-            p.getFixBytes(length)
-        return ASN1Parser(p.bytes[markIndex:p.index])
+            self.length = self._getASN1Length(p)
+            self.value = p.getFixBytes(self.length)
+    
+        def getChild(self, which):
+            p = self.Parser(self.value)
+            for x in range(which+1):
+                markIndex = p.index
+                p.get(1)
+                length = self._getASN1Length(p)
+                p.getFixBytes(length)
+            return ASN1Parser(p.bytes[markIndex:p.index])
+    
+        def _getASN1Length(self, p):
+            firstLength = p.get(1)
+            if firstLength<=127:
+                return firstLength
+            else:
+                lengthLength = firstLength & 0x7F
+                return p.get(lengthLength)
+
+    class AES(object):
+        def __init__(self, key):
+            self._aes = _AES.new(key, _AES.MODE_CBC)
+
+        def decrypt(self, data):
+            return self._aes.decrypt(data)
+
+    class RSA(object):
+        def __init__(self, der):
+            key = ASN1Parser([ord(x) for x in der])
+            key = [key.getChild(x).value for x in xrange(1, 4)]
+            key = [self.bytesToNumber(v) for v in key]
+            self._rsa = _RSA.construct(key)
+
+        def bytesToNumber(self, bytes):
+            total = 0L
+            for byte in bytes:
+                total = (total << 8) + byte
+            return total
+    
+        def decrypt(self, data):
+            return self._rsa.decrypt(data)
 
-    def _getASN1Length(self, p):
-        firstLength = p.get(1)
-        if firstLength<=127:
-            return firstLength
-        else:
-            lengthLength = firstLength & 0x7F
-            return p.get(lengthLength)
+    return (AES, RSA)
 
+def _load_crypto():
+    AES = RSA = None
+    for loader in (_load_crypto_libcrypto, _load_crypto_pycrypto):
+        try:
+            AES, RSA = loader()
+            break
+        except (ImportError, ADEPTError):
+            pass
+    return (AES, RSA)
+AES, RSA = _load_crypto()
+
+META_NAMES = ('mimetype', 'META-INF/rights.xml', 'META-INF/encryption.xml')
+NSMAP = {'adept': 'http://ns.adobe.com/adept',
+         'enc': 'http://www.w3.org/2001/04/xmlenc#'}
 
 class ZipInfo(zipfile.ZipInfo):
     def __init__(self, *args, **kwargs):
@@ -152,11 +270,10 @@ class ZipInfo(zipfile.ZipInfo):
         super(ZipInfo, self).__init__(*args, **kwargs)
         self.compress_type = compress_type
 
-
 class Decryptor(object):
     def __init__(self, bookkey, encryption):
         enc = lambda tag: '{%s}%s' % (NSMAP['enc'], tag)
-        self._aes = AES.new(bookkey, AES.MODE_CBC)
+        self._aes = AES(bookkey)
         encryption = etree.fromstring(encryption)
         self._encrypted = encrypted = set()
         expr = './%s/%s/%s' % (enc('EncryptedData'), enc('CipherData'),
@@ -165,7 +282,7 @@ class Decryptor(object):
             path = elem.get('URI', None)
             if path is not None:
                 encrypted.add(path)
-    
+
     def decompress(self, bytes):
         dc = zlib.decompressobj(-15)
         bytes = dc.decompress(bytes)
@@ -173,7 +290,7 @@ class Decryptor(object):
         if ex:
             bytes = bytes + ex
         return bytes
-    
+
     def decrypt(self, path, data):
         if path in self._encrypted:
             data = self._aes.decrypt(data)[16:]
@@ -181,16 +298,12 @@ class Decryptor(object):
             data = self.decompress(data)
         return data
 
-
-class ADEPTError(Exception):
-    pass
-
 def cli_main(argv=sys.argv):
     progname = os.path.basename(argv[0])
     if AES is None:
-        print "%s: This script requires PyCrypto, which must be installed " \
-              "separately.  Read the top-of-script comment for details." % \
-              (progname,)
+        print "%s: This script requires OpenSSL or PyCrypto, which must be" \
+              " installed separately.  Read the top-of-script comment for" \
+              " details." % (progname,)
         return 1
     if len(argv) != 4:
         print "usage: %s KEYFILE INBOOK OUTBOOK" % (progname,)
@@ -198,9 +311,7 @@ def cli_main(argv=sys.argv):
     keypath, inpath, outpath = argv[1:]
     with open(keypath, 'rb') as f:
         keyder = f.read()
-    key = ASN1Parser([ord(x) for x in keyder])
-    key = [bytesToNumber(key.getChild(x).value) for x in xrange(1, 4)]
-    rsa = RSA.construct(key)
+    rsa = RSA(keyder)
     with closing(ZipFile(open(inpath, 'rb'))) as inf:
         namelist = set(inf.namelist())
         if 'META-INF/rights.xml' not in namelist or \
@@ -227,7 +338,6 @@ def cli_main(argv=sys.argv):
                 outf.writestr(path, decryptor.decrypt(path, data))
     return 0
 
-
 class DecryptionDialog(Tkinter.Frame):
     def __init__(self, root):
         Tkinter.Frame.__init__(self, root, border=5)
@@ -328,8 +438,9 @@ def gui_main():
         root.withdraw()
         tkMessageBox.showerror(
             "INEPT EPUB Decrypter",
-            "This script requires PyCrypto, which must be installed "
-            "separately.  Read the top-of-script comment for details.")
+            "This script requires OpenSSL or PyCrypto, which must be"
+            " installed separately.  Read the top-of-script comment for"
+            " details.")
         return 1
     root.title('INEPT EPUB Decrypter')
     root.resizable(True, False)
index 4a5d86803d6db9c64d496e161c16ae6a12f4d622..3756ae318ef11e65f7739ac0a1c3d8be9ddbb175 100644 (file)
@@ -1,25 +1,38 @@
 #! /usr/bin/python
-
-# ineptkey.pyw, version 4.4
-# ineptkeyv44
-
-# To run this program install Python 2.6 from http://www.python.org/download/
-# and PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto
-# (make sure to install the version for Python 2.6).  Save this script file as
-# ineptkey.pyw and double-click on it to run it.  It will create a file named
-# adeptkey.der in the same directory.  These are your ADEPT user keys.
+# -*- coding: utf-8 -*-
+
+# ineptkey.pyw, version 5
+# Copyright © 2009-2010 i♥cabbages
+
+# Released under the terms of the GNU General Public Licence, version 3 or
+# later.  <http://www.gnu.org/licenses/>
+
+# Windows users: Before running this program, you must first install Python 2.6
+#   from <http://www.python.org/download/> and PyCrypto from
+#   <http://www.voidspace.org.uk/python/modules.shtml#pycrypto> (make certain
+#   to install the version for Python 2.6).  Then save this script file as
+#   ineptkey.pyw and double-click on it to run it.  It will create a file named
+#   adeptkey.der in the same directory.  This is your ADEPT user key.
+#
+# Mac OS X users: Save this script file as ineptkey.pyw.  You can run this
+#   program from the command line (pythonw ineptkey.pyw) or by double-clicking
+#   it when it has been associated with PythonLauncher.  It will create a file
+#   named adeptkey.der in the same directory.  This is your ADEPT user key.
 
 # Revision history:
 #   1 - Initial release, for Adobe Digital Editions 1.7
 #   2 - Better algorithm for finding pLK; improved error handling
 #   3 - Rename to INEPT
+#   4 - Series of changes by joblack (and others?) --
 #   4.1 - quick beta fix for ADE 1.7.2 (anon)
 #   4.2 - added old 1.7.1 processing
 #   4.3 - better key search
 #   4.4 - Make it working on 64-bit Python
+#   5 - Clean up and improve 4.x changes;
+#       Clean up and merge OS X support by unknown
 
 """
-Retrieve Adobe ADEPT user key under Windows.
+Retrieve Adobe ADEPT user key.
 """
 
 from __future__ import with_statement
@@ -28,246 +41,305 @@ __license__ = 'GPL v3'
 
 import sys
 import os
-from struct import pack
-from ctypes import windll, c_char_p, c_wchar_p, c_uint, POINTER, byref, \
-    create_unicode_buffer, create_string_buffer, CFUNCTYPE, addressof, \
-    string_at, Structure, c_void_p, cast, c_ulonglong, \
-    sizeof, c_void_p, c_size_t
-
-import _winreg as winreg
+import struct
 import Tkinter
 import Tkconstants
 import tkMessageBox
 import traceback
-import hashlib
-import pickle
-
-
-try:
-    from Crypto.Cipher import AES
-except ImportError:
-    AES = None
 
+class ADEPTError(Exception):
+    pass
 
-DEVICE_KEY = 'Software\\Adobe\\Adept\\Device'
-PRIVATE_LICENCE_KEY = 'Software\\Adobe\\Adept\\Activation\\%04d'
-PRIVATE_LICENCE_KEY_KEY = 'Software\\Adobe\\Adept\\Activation\\%04d\\%04d'
-ACTIVATION = 'Software\\Adobe\\Adept\\Activation\\'
-
-MAX_PATH = 255
+if sys.platform.startswith('win'):
+    from ctypes import windll, c_char_p, c_wchar_p, c_uint, POINTER, byref, \
+        create_unicode_buffer, create_string_buffer, CFUNCTYPE, addressof, \
+        string_at, Structure, c_void_p, cast, c_size_t, memmove
+    from ctypes.wintypes import LPVOID, DWORD, BOOL
+    import _winreg as winreg
 
-kernel32 = windll.kernel32
-advapi32 = windll.advapi32
-crypt32 = windll.crypt32
+    try:
+        from Crypto.Cipher import AES
+    except ImportError:
+        AES = None
 
+    DEVICE_KEY_PATH = r'Software\Adobe\Adept\Device'
+    PRIVATE_LICENCE_KEY_PATH = r'Software\Adobe\Adept\Activation'
 
-class ADEPTError(Exception):
-    pass
+    MAX_PATH = 255
 
+    kernel32 = windll.kernel32
+    advapi32 = windll.advapi32
+    crypt32 = windll.crypt32
 
-def GetSystemDirectory():
-    GetSystemDirectoryW = kernel32.GetSystemDirectoryW
-    GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint]
-    GetSystemDirectoryW.restype = c_uint
     def GetSystemDirectory():
-        buffer = create_unicode_buffer(MAX_PATH + 1)
-        GetSystemDirectoryW(buffer, len(buffer))
-        return buffer.value
-    return GetSystemDirectory
-GetSystemDirectory = GetSystemDirectory()
-
-
-def GetVolumeSerialNumber():
-    GetVolumeInformationW = kernel32.GetVolumeInformationW
-    GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint,
-                                      POINTER(c_uint), POINTER(c_uint),
-                                      POINTER(c_uint), c_wchar_p, c_uint]
-    GetVolumeInformationW.restype = c_uint
-    def GetVolumeSerialNumber(path):
-        vsn = c_uint(0)
-        GetVolumeInformationW(path, None, 0, byref(vsn), None, None, None, 0)
-        return vsn.value
-    return GetVolumeSerialNumber
-GetVolumeSerialNumber = GetVolumeSerialNumber()
-
-
-def GetUserName():
-    GetUserNameW = advapi32.GetUserNameW
-    GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)]
-    GetUserNameW.restype = c_uint
+        GetSystemDirectoryW = kernel32.GetSystemDirectoryW
+        GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint]
+        GetSystemDirectoryW.restype = c_uint
+        def GetSystemDirectory():
+            buffer = create_unicode_buffer(MAX_PATH + 1)
+            GetSystemDirectoryW(buffer, len(buffer))
+            return buffer.value
+        return GetSystemDirectory
+    GetSystemDirectory = GetSystemDirectory()
+
+    def GetVolumeSerialNumber():
+        GetVolumeInformationW = kernel32.GetVolumeInformationW
+        GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint,
+                                          POINTER(c_uint), POINTER(c_uint),
+                                          POINTER(c_uint), c_wchar_p, c_uint]
+        GetVolumeInformationW.restype = c_uint
+        def GetVolumeSerialNumber(path):
+            vsn = c_uint(0)
+            GetVolumeInformationW(
+                path, None, 0, byref(vsn), None, None, None, 0)
+            return vsn.value
+        return GetVolumeSerialNumber
+    GetVolumeSerialNumber = GetVolumeSerialNumber()
+
     def GetUserName():
-        buffer = create_unicode_buffer(32)
-        size = c_uint(len(buffer))
-        while not GetUserNameW(buffer, byref(size)):
-            buffer = create_unicode_buffer(len(buffer) * 2)
-            size.value = len(buffer)
-        return buffer.value.encode('utf-16-le')[::2]
-    return GetUserName
-GetUserName = GetUserName()
-
-if sizeof(c_void_p) == 4:
-    ## 32-bit Python
-    CPUID0_INSNS = create_string_buffer("\x53\x31\xc0\x0f\xa2\x8b\x44\x24\x08\x89"
-                                        "\x18\x89\x50\x04\x89\x48\x08\x5b\xc3")
-    def cpuid0():
-        buffer = create_string_buffer(12)
-        cpuid0__ = CFUNCTYPE(c_char_p)(addressof(CPUID0_INSNS))
-        def cpuid0():
-            cpuid0__(buffer)
-            return buffer.raw
-        return cpuid0
-    cpuid0 = cpuid0()
+        GetUserNameW = advapi32.GetUserNameW
+        GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)]
+        GetUserNameW.restype = c_uint
+        def GetUserName():
+            buffer = create_unicode_buffer(32)
+            size = c_uint(len(buffer))
+            while not GetUserNameW(buffer, byref(size)):
+                buffer = create_unicode_buffer(len(buffer) * 2)
+                size.value = len(buffer)
+            return buffer.value.encode('utf-16-le')[::2]
+        return GetUserName
+    GetUserName = GetUserName()
 
-    CPUID1_INSNS = create_string_buffer("\x53\x31\xc0\x40\x0f\xa2\x5b\xc3")
-    cpuid1 = CFUNCTYPE(c_uint)(addressof(CPUID1_INSNS))
-else:
-    ## 64 bit Python
-
-    # In 64-bit we cannot execute instructions stored in a string because
-    # the O.S. prevents that to defend against buffer overrun attacks.
-    # Therefore we have to allocate a block of memory with the execute
-    # permission and copy our code into it.
-    
-    NULL = c_void_p(0)
     PAGE_EXECUTE_READWRITE = 0x40
     MEM_COMMIT  = 0x1000
     MEM_RESERVE = 0x2000
 
-    VirtualAlloc = windll.kernel32.VirtualAlloc
-    VirtualAlloc.restype = c_void_p
-    VirtualAlloc.argtypes = (c_void_p, c_size_t, c_uint, c_uint)
-
-    from ctypes import memmove
-    memmove.restype = c_void_p
-    memmove.argtypes = (c_void_p, c_void_p, c_size_t)
-
-    CPUID0_INSNS = (b"\x55"             # push   %rbp
-                    "\x48\x89\xe5"      # mov    %rsp,%rbp
-                    "\x48\x89\x4d\xf8"  # mov    %rcx,-0x8(%rbp)
-                    "\x31\xc0"          # xor    %eax,%eax
-                    "\x0f\xa2"          # cpuid  
-                    "\x48\x8b\x45\xf8"  # mov    -0x8(%rbp),%rax
-                    "\x89\x18"          # mov    %ebx,(%rax)
-                    "\x89\x50\x04"      # mov    %edx,0x4(%rax)
-                    "\x89\x48\x08"      # mov    %ecx,0x8(%rax)
-                    "\x48\x8b\x45\xf8"  # mov    -0x8(%rbp),%rax
-                    "\xc9"              # leave
-                    "\xc3"              # ret
-                    )
-
-    CPUID1_INSNS = (b"\x31\xc0"         # xor    %eax,%eax
-                    "\xff\xc0"          # inc    %eax
-                    "\x0f\xa2"          # cpuid  
-                    "\xc3"              # ret
-                    )
-
-    insnlen0 = len(CPUID0_INSNS)
-    insnlen1 = len(CPUID1_INSNS)
-    insnlen = insnlen0 + insnlen1
-
-    code_addr = (VirtualAlloc(NULL, insnlen,
-                    MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE))
-
-    if code_addr is None:
-        raise ADEPTError("Failed to allocate memory")
-
-    memmove(code_addr, CPUID0_INSNS + CPUID1_INSNS, insnlen)
+    def VirtualAlloc():
+        _VirtualAlloc = kernel32.VirtualAlloc
+        _VirtualAlloc.argtypes = [LPVOID, c_size_t, DWORD, DWORD]
+        _VirtualAlloc.restype = LPVOID
+        def VirtualAlloc(addr, size, alloctype=(MEM_COMMIT | MEM_RESERVE),
+                         protect=PAGE_EXECUTE_READWRITE):
+            return _VirtualAlloc(addr, size, alloctype, protect)
+        return VirtualAlloc
+    VirtualAlloc = VirtualAlloc()
+
+    MEM_RELEASE = 0x8000
+
+    def VirtualFree():
+        _VirtualFree = kernel32.VirtualFree
+        _VirtualFree.argtypes = [LPVOID, c_size_t, DWORD]
+        _VirtualFree.restype = BOOL
+        def VirtualFree(addr, size=0, freetype=MEM_RELEASE):
+            return _VirtualFree(addr, size, freetype)
+        return VirtualFree
+    VirtualFree = VirtualFree()
+
+    class NativeFunction(object):
+        def __init__(self, restype, argtypes, insns):
+            self._buf = buf = VirtualAlloc(None, len(insns))
+            memmove(buf, insns, len(insns))
+            ftype = CFUNCTYPE(restype, *argtypes)
+            self._native = ftype(buf)
+
+        def __call__(self, *args):
+            return self._native(*args)
+
+        def __del__(self):
+            if self._buf is not None:
+                VirtualFree(self._buf)
+                self._buf = None
+
+    if struct.calcsize("P") == 4:
+        CPUID0_INSNS = (
+            "\x53"             # push   %ebx
+            "\x31\xc0"         # xor    %eax,%eax
+            "\x0f\xa2"         # cpuid
+            "\x8b\x44\x24\x08" # mov    0x8(%esp),%eax
+            "\x89\x18"         # mov    %ebx,0x0(%eax)
+            "\x89\x50\x04"     # mov    %edx,0x4(%eax)
+            "\x89\x48\x08"     # mov    %ecx,0x8(%eax)
+            "\x5b"             # pop    %ebx
+            "\xc3"             # ret
+        )
+        CPUID1_INSNS = (
+            "\x53"             # push   %ebx
+            "\x31\xc0"         # xor    %eax,%eax
+            "\x40"             # inc    %eax
+            "\x0f\xa2"         # cpuid
+            "\x5b"             # pop    %ebx
+            "\xc3"             # ret
+        )
+    else:
+        CPUID0_INSNS = (
+            "\x49\x89\xd8"     # mov    %rbx,%r8
+            "\x49\x89\xc9"     # mov    %rcx,%r9
+            "\x48\x31\xc0"     # xor    %rax,%rax
+            "\x0f\xa2"         # cpuid
+            "\x4c\x89\xc8"     # mov    %r9,%rax
+            "\x89\x18"         # mov    %ebx,0x0(%rax)
+            "\x89\x50\x04"     # mov    %edx,0x4(%rax)
+            "\x89\x48\x08"     # mov    %ecx,0x8(%rax)
+            "\x4c\x89\xc3"     # mov    %r8,%rbx
+            "\xc3"             # retq
+        )
+        CPUID1_INSNS = (
+            "\x53"             # push   %rbx
+            "\x48\x31\xc0"     # xor    %rax,%rax
+            "\x48\xff\xc0"     # inc    %rax
+            "\x0f\xa2"         # cpuid
+            "\x5b"             # pop    %rbx
+            "\xc3"             # retq
+        )
 
     def cpuid0():
-        buffer = create_string_buffer(12)
-        cpuid0__ = CFUNCTYPE(c_ulonglong, c_char_p)(code_addr)
+        _cpuid0 = NativeFunction(None, [c_char_p], CPUID0_INSNS)
+        buf = create_string_buffer(12)
         def cpuid0():
-            cpuid0__(buffer)
-            return buffer.raw
+            _cpuid0(buf)
+            return buf.raw
         return cpuid0
     cpuid0 = cpuid0()
 
-    cpuid1 =  CFUNCTYPE(c_ulonglong)(code_addr + insnlen0)
-
-class DataBlob(Structure):
-    _fields_ = [('cbData', c_uint),
-                ('pbData', c_void_p)]
-DataBlob_p = POINTER(DataBlob)
-
-def CryptUnprotectData():
-    _CryptUnprotectData = crypt32.CryptUnprotectData
-    _CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p,
-                                   c_void_p, c_void_p, c_uint, DataBlob_p]
-    _CryptUnprotectData.restype = c_uint
-    def CryptUnprotectData(indata, entropy):
-        indatab = create_string_buffer(indata)
-        indata = DataBlob(len(indata), cast(indatab, c_void_p))
-        entropyb = create_string_buffer(entropy)
-        entropy = DataBlob(len(entropy), cast(entropyb, c_void_p))
-        outdata = DataBlob()
-        if not _CryptUnprotectData(byref(indata), None, byref(entropy),
-                                   None, None, 0, byref(outdata)):
-            raise ADEPTError("Failed to decrypt user key key (sic)")
-        return string_at(outdata.pbData, outdata.cbData)
-    return CryptUnprotectData
-CryptUnprotectData = CryptUnprotectData()
-
-
-def retrieve_key(keypath):
-    root = GetSystemDirectory().split('\\')[0] + '\\'
-    serial = GetVolumeSerialNumber(root)
-    vendor = cpuid0()
-    signature = pack('>I', cpuid1())[1:]
-    user = GetUserName()
-    entropy = pack('>I12s3s13s', serial, vendor, signature, user)
-    cuser = winreg.HKEY_CURRENT_USER
-    try:
-        regkey = winreg.OpenKey(cuser, DEVICE_KEY)
-    except WindowsError:
-        raise ADEPTError("Adobe Digital Editions not activated")
-    device = winreg.QueryValueEx(regkey, 'key')[0]
-    keykey = CryptUnprotectData(device, entropy)
-    userkey = None
-    pkcs = None
-    keys = {}
-    counter = 0
-    for i in xrange(0, 16):
-        skey = PRIVATE_LICENCE_KEY % i
+    cpuid1 = NativeFunction(c_uint, [], CPUID1_INSNS)
+
+    class DataBlob(Structure):
+        _fields_ = [('cbData', c_uint),
+                    ('pbData', c_void_p)]
+    DataBlob_p = POINTER(DataBlob)
+
+    def CryptUnprotectData():
+        _CryptUnprotectData = crypt32.CryptUnprotectData
+        _CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p,
+                                       c_void_p, c_void_p, c_uint, DataBlob_p]
+        _CryptUnprotectData.restype = c_uint
+        def CryptUnprotectData(indata, entropy):
+            indatab = create_string_buffer(indata)
+            indata = DataBlob(len(indata), cast(indatab, c_void_p))
+            entropyb = create_string_buffer(entropy)
+            entropy = DataBlob(len(entropy), cast(entropyb, c_void_p))
+            outdata = DataBlob()
+            if not _CryptUnprotectData(byref(indata), None, byref(entropy),
+                                       None, None, 0, byref(outdata)):
+                raise ADEPTError("Failed to decrypt user key key (sic)")
+            return string_at(outdata.pbData, outdata.cbData)
+        return CryptUnprotectData
+    CryptUnprotectData = CryptUnprotectData()
+
+    def retrieve_key(keypath):
+        if AES is None:
+            tkMessageBox.showerror(
+                "ADEPT Key",
+                "This script requires PyCrypto, which must be installed "
+                "separately.  Read the top-of-script comment for details.")
+            return False
+        root = GetSystemDirectory().split('\\')[0] + '\\'
+        serial = GetVolumeSerialNumber(root)
+        vendor = cpuid0()
+        signature = struct.pack('>I', cpuid1())[1:]
+        user = GetUserName()
+        entropy = struct.pack('>I12s3s13s', serial, vendor, signature, user)
+        cuser = winreg.HKEY_CURRENT_USER
         try:
-            regkey = winreg.OpenKey(cuser, skey)
+            regkey = winreg.OpenKey(cuser, DEVICE_KEY_PATH)
         except WindowsError:
-            break
-        type = winreg.QueryValueEx(regkey, None)[0]
-        # obfuscation technique
-        if type != 'credentials':
-            continue
-        for j in xrange(0, 16):
-            plkkey = PRIVATE_LICENCE_KEY_KEY  % (i, j)
+            raise ADEPTError("Adobe Digital Editions not activated")
+        device = winreg.QueryValueEx(regkey, 'key')[0]
+        keykey = CryptUnprotectData(device, entropy)
+        userkey = None
+        try:
+            plkroot = winreg.OpenKey(cuser, PRIVATE_LICENCE_KEY_PATH)
+        except WindowsError:
+            raise ADEPTError("Could not locate ADE activation")
+        for i in xrange(0, 16):
             try:
-                regkey = winreg.OpenKey(cuser, plkkey)                
+                plkparent = winreg.OpenKey(plkroot, "%04d" % (i,))
             except WindowsError:
                 break
-            type = winreg.QueryValueEx(regkey, None)[0]            
-            if type != 'privateLicenseKey':
+            ktype = winreg.QueryValueEx(plkparent, None)[0]
+            if ktype != 'credentials':
                 continue
-            userkey = winreg.QueryValueEx(regkey, 'value')[0]
-            break
-        for j in xrange(0, 16):
-            plkkey = PRIVATE_LICENCE_KEY_KEY  % (i, j)
-            try:
-                pkcs = winreg.OpenKey(cuser, plkkey)   
-            except WindowsError:
+            for j in xrange(0, 16):
+                try:
+                    plkkey = winreg.OpenKey(plkparent, "%04d" % (j,))
+                except WindowsError:
+                    break
+                ktype = winreg.QueryValueEx(plkkey, None)[0]
+                if ktype != 'privateLicenseKey':
+                    continue
+                userkey = winreg.QueryValueEx(plkkey, 'value')[0]
+                break
+            if userkey is not None:
                 break
-            type = winreg.QueryValueEx(pkcs, None)[0]
-            if type != 'pkcs12':
+        if userkey is None:
+            raise ADEPTError('Could not locate privateLicenseKey')
+        userkey = userkey.decode('base64')
+        userkey = AES.new(keykey, AES.MODE_CBC).decrypt(userkey)
+        userkey = userkey[26:-ord(userkey[-1])]
+        with open(keypath, 'wb') as f:
+            f.write(userkey)
+        return True
+
+elif sys.platform.startswith('darwin'):
+    import xml.etree.ElementTree as etree
+    import Carbon.File
+    import Carbon.Folder
+    import Carbon.Folders
+    import MacOS
+
+    ACTIVATION_PATH = 'Adobe/Digital Editions/activation.dat'
+    NSMAP = {'adept': 'http://ns.adobe.com/adept',
+             'enc': 'http://www.w3.org/2001/04/xmlenc#'}
+
+    def find_folder(domain, dtype):
+        try:
+            fsref = Carbon.Folder.FSFindFolder(domain, dtype, False)
+            return Carbon.File.pathname(fsref)
+        except MacOS.Error:
+            return None
+
+    def find_app_support_file(subpath):
+        dtype = Carbon.Folders.kApplicationSupportFolderType
+        for domain in Carbon.Folders.kUserDomain, Carbon.Folders.kLocalDomain:
+            path = find_folder(domain, dtype)
+            if path is None:
                 continue
-            pkcs = winreg.QueryValueEx(pkcs, 'value')[0]
-            break
-    if pkcs is None:       
-        raise ADEPTError('Could not locate PKCS specification')
-    if userkey is None:
-        raise ADEPTError('Could not locate privateLicenseKey')
-    userkey = userkey.decode('base64')
-    userkey = AES.new(keykey, AES.MODE_CBC).decrypt(userkey)
-    userkey = userkey[26:-ord(userkey[-1])]
-    with open(keypath, 'wb') as f:
-        f.write(userkey)
-    return
+            path = os.path.join(path, subpath)
+            if os.path.isfile(path):
+                return path
+        return None
+
+    def retrieve_key(keypath):
+        actpath = find_app_support_file(ACTIVATION_PATH)
+        if actpath is None:
+            raise ADEPTError("Could not locate ADE activation")
+        tree = etree.parse(actpath)
+        adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag)
+        expr = '//%s/%s' % (adept('credentials'), adept('privateLicenseKey'))
+        userkey = tree.findtext(expr)
+        userkey = userkey.decode('base64')
+        userkey = userkey[26:]
+        with open(keypath, 'wb') as f:
+            f.write(userkey)
+        return True
+
+elif sys.platform.startswith('cygwin'):
+    def retrieve_key(keypath):
+        tkMessageBox.showerror(
+            "ADEPT Key",
+            "This script requires a Windows-native Python, and cannot be run "
+            "under Cygwin.  Please install a Windows-native Python and/or "
+            "check your file associations.")
+        return False
+
+else:
+    def retrieve_key(keypath):
+        tkMessageBox.showerror(
+            "ADEPT Key",
+            "This script only supports Windows and Mac OS X.  For Linux "
+            "you should be able to run ADE and this script under Wine (with "
+            "an appropriate version of Windows Python installed).")
+        return False
 
 class ExceptionDialog(Tkinter.Frame):
     def __init__(self, root, text):
@@ -279,33 +351,27 @@ class ExceptionDialog(Tkinter.Frame):
         self.text.pack(fill=Tkconstants.BOTH, expand=1)
         self.text.insert(Tkconstants.END, text)
 
-
 def main(argv=sys.argv):
     root = Tkinter.Tk()
     root.withdraw()
     progname = os.path.basename(argv[0])
-    if AES is None:
-        tkMessageBox.showerror(
-            "ADEPT Key",
-            "This script requires PyCrypto, which must be installed "
-            "separately.  Read the top-of-script comment for details.")
-        return 1
     keypath = 'adeptkey.der'
+    success = False
     try:
-        retrieve_key(keypath)
+        success = retrieve_key(keypath)
     except ADEPTError, e:
         tkMessageBox.showerror("ADEPT Key", "Error: " + str(e))
-        return 1
     except Exception:
         root.wm_state('normal')
         root.title('ADEPT Key')
         text = traceback.format_exc()
         ExceptionDialog(root, text).pack(fill=Tkconstants.BOTH, expand=1)
         root.mainloop()
+    if not success:
         return 1
     tkMessageBox.showinfo(
         "ADEPT Key", "Key successfully retrieved to %s" % (keypath))
     return 0
 
 if __name__ == '__main__':
-    sys.exit(main())
\ No newline at end of file
+    sys.exit(main())
diff --git a/Adobe_EPUB_Tools/ineptkeymac.pyw b/Adobe_EPUB_Tools/ineptkeymac.pyw
deleted file mode 100644 (file)
index 0dd1307..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-#! /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())
diff --git a/Kindle_Mobi_Tools/LZskindle4PCv1_1/EZskindle4PCv1_1_1.cpp b/Kindle_Mobi_Tools/LZskindle4PCv1_1/EZskindle4PCv1_1_1.cpp
new file mode 100644 (file)
index 0000000..535df90
--- /dev/null
@@ -0,0 +1,88 @@
+#include <cstdlib>
+#include <iostream>
+#include <conio.h>
+#include <fstream>
+
+using namespace std;
+
+int main(int argc, char *argv[])
+{
+// Variables
+       int  TopazTrue    = 0;
+       int  strlength    = 0;
+       char uinfile[80];
+       char outfile[80];
+       char command[80];
+       char buffer[80];
+
+// String initialization
+       strcpy(uinfile,"");
+       strcpy(outfile,"");
+       strcpy(buffer,"");
+       strcpy(command,"skindle ");          // string preloaded with "skindle "
+       
+       
+    cout << "\n\n\n     Please enter the name of the book to be converted:\n\n     ";
+    cout << "     Don't forget the prc file extension!\n\n     ";
+    cout << "     Watch out for zeros and Os. Zeros are skinny and Os are fat.\n\n\n     ";
+
+      cin >> uinfile;                             // get file name of the book to be converted from user
+
+
+         ifstream infile(uinfile);
+         infile.getline(buffer,4);
+
+
+         if (strncmp (buffer,"TPZ",3)==0)      // open file and test first 3 char if TPZ then book is topaz
+         { 
+                TopazTrue = 1;                             // This is a Topaz file
+         }
+
+
+         strlength = strlen(uinfile);
+
+         if(strlength > 13)
+           {
+         strncat(outfile,uinfile,10);                // Create output file name using first 10 char of input file name
+           }
+         else
+           {
+              strncat(outfile,uinfile, (strlength - 4));  // If file name is less than 10 characters
+           }
+         if(TopazTrue == 1)                         // This is Topaz Book
+                {
+                                strcat(command,"-d ");          // Add the topaz switch to the command line
+
+                                strcat(outfile,".tpz");         // give tpz file extension to topaz output file
+                } // end of TopazTrue
+         else
+         {
+                 strcat(outfile,".azw"); 
+         } // if not Topaz make it azw
+
+         strcat(command,"-i ");                     // Add the input switch to the command line
+         strcat(command,uinfile);                    // add the input file name to the command line
+         strcat(command," -o ");                    // add the output switch to the command line
+         strcat(command,outfile);                   // Add the output file name to the command line
+
+       cout << "\n\n   The skindle program is called here.\n";
+       cout << "   Any errors reported between here and \"The command line used was:\"\n";
+       cout << "   Are errors from the skindle program. Not EZskindle4PC.\n\n";
+         
+
+        system(command);                            // call skindle program to convert the book
+         
+         
+       cout << "\n\n   The command line used was:\n\n";
+       cout << " " << command << "\n";
+       cout << "\n\n\n   Please note the output file is created from the input";
+       cout << "\n   file name. The file extension is changed to tpz for Topaz";
+       cout << "\n   files and to azw for non-Topaz files. Also, _EBOK is removed ";
+       cout << "\n   from the file name.  This is to make it eaiser to identify ";
+    cout << "\n   the file with no DRM.";
+
+       
+
+    system("PAUSE");
+    return EXIT_SUCCESS;
+}
diff --git a/Kindle_Mobi_Tools/LZskindle4PCv1_1/EZskindle4PCv1_1_1.exe b/Kindle_Mobi_Tools/LZskindle4PCv1_1/EZskindle4PCv1_1_1.exe
new file mode 100644 (file)
index 0000000..b40343c
Binary files /dev/null and b/Kindle_Mobi_Tools/LZskindle4PCv1_1/EZskindle4PCv1_1_1.exe differ
diff --git a/Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle Read Me.txt b/Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle Read Me.txt
new file mode 100644 (file)
index 0000000..59d97e0
--- /dev/null
@@ -0,0 +1,44 @@
+LZskindle4PCv1_1    The Lazy skindle program for those who are typing impared
+
+To setup:
+
+1.  Create a new folder:   example C:\skindle
+
+2.  Place LZskindle4PCv1_1.exe and skindle.exe in this folder.
+
+3.  Create 2 subfolders:    C:\skindle\input 
+    and                     C:\skindle\output
+
+
+To run:
+
+1.  Copy the book(s) you wish to remove DRM from into the input directory 
+(leave the originals in my kindle folder).
+
+2.  Double click on LZskindle4PCv1_0.exe
+
+3.  A DOS window will open and will show skindle being called for 
+each book in the input directory.
+
+4.  The books with the DRM removed will now be in the output directory.
+
+Rev1_1
+
+fixed program to allow any file extension.  My testing indicates that 
+skindle does not care what file extension a file has.  If it is a file type
+that it can convert it will.  If the file is not compatible it will close
+and give an unknown file type message.
+
+Rev1_0
+
+If the program is run with no files in the input directory you will get a 
+\93File not Found\94 error and the program will terminate.
+
+PLEASE USE ONLY FOR YOUR PERSONAL USE \96 ON BOOKS YOU PAID FOR!!
+
+This program is provided to allow you to archive your library in a format that 
+will outlast the kindle.  Technology moves on and you should not have to reinvest 
+in an entire new library when the Kindle is obsolete.  Please do not use this program 
+for piracy.
+
+
diff --git a/Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle4PCv1_1.cpp b/Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle4PCv1_1.cpp
new file mode 100644 (file)
index 0000000..1adaa93
--- /dev/null
@@ -0,0 +1,150 @@
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+//#include <conio.h>
+
+using namespace std;
+
+int main(int argc, char *argv[])
+{
+    // Variable Declarations ??
+    char buffer[80];
+    int error = 0;
+//    int YesNo = 0;
+//    int exit  = 0;
+ // Variables  EZskindle4PC 
+       int  TopazTrue    = 0;
+       int  strlength    = 0;
+       char uinfile[80];
+       char outfile[80];
+       char command[80];
+       char buffer2[20];
+       char tempfile[80];
+   
+  // Initialize strings
+       strcpy(uinfile,"");
+       strcpy(outfile,"");
+       strcpy(buffer,"");
+       strcpy(buffer2,"");
+       strcpy(command,"skindle ");          // string preloaded with "skindle "
+
+      
+   //// Beginning of program code //////////////////////////////////////////////////////////// 
+
+    system("dir /b .\\input\\*.* > books.txt");  // Create txt file with list of books
+                                                 // No testing of file type being done
+                                                 // I am letting skindle determing if valid 
+                                                 // file type
+    //  Read in the list of book file names
+    
+   ifstream infile("books.txt");   
+
+    do  // while not end of file
+      {
+        infile.getline(buffer,50);  // load the first 50 characters of the line to buffer
+        
+        if(strcmp(buffer, "")!= 0)  // If there is file name in the buffer do this on last loop buffer will be empty
+         {
+            strcpy(uinfile,buffer);      // load file name from buffer
+
+               strcpy(tempfile,".\\input\\");  // load directory name for input files
+            strcat(tempfile,buffer);        // load the file name
+               ifstream infile2(tempfile);     // open the book file for reading
+               infile2.getline(buffer2,4);     // load first 4 char from file
+
+            infile2.close();    // close the book file
+
+
+               if (strncmp (buffer2,"TPZ",3)==0)      // open file and test first 3 char if TPZ then book is topaz
+                 { 
+                        TopazTrue = 1;                             // This is a Topaz file
+                 }
+
+
+           strlength = strlen(uinfile);
+
+              if(strlength > 13)
+                {
+               strncat(outfile,uinfile,10);                // Create output file name using first 10 char of input file name
+                }
+               else
+                 {
+                    strncat(outfile,uinfile, (strlength - 4));  // If file name is less than 10 characters
+                 }
+             if(TopazTrue == 1)                         // This is Topaz Book
+                {
+                                strcat(command,"-d ");          // Add the topaz switch to the command line
+
+                                strcat(outfile,".tpz");         // give tpz file extension to topaz output file
+                } // end of TopazTrue
+              else
+               {
+                      strcat(outfile,".azw"); 
+               } // if not Topaz make it azw
+
+         strcat(command,"-i ");                     // Add the input switch to the command line
+         strcat(command,".\\input\\");              // Add the input directory to the command line
+            strcat(command,uinfile);                   // add the input file name to the command line
+            strcat(command," -o ");                    // add the output switch to the command line
+            strcat(command,".\\output\\");             // Add directory for out files
+            strcat(command,outfile);                   // Add the output file name to the command line
+
+            cout << "\n\n   The skindle program is called here.\n";
+            cout << "   Any errors reported between here and \"The command line used was:\"\n";
+            cout << "   Are errors from the skindle program. Not EZskindle4PC.\n\n";
+         
+
+            system(command);                            // call skindle program to convert the book
+         
+         
+            cout << "\n\n   The command line used was:\n\n";
+            cout << " " << command << "\n\n\n\n";
+
+
+       }// end of file name in the buffer required to prevent execution on EOF
+
+
+          strcpy(command,"skindle ");          // reset strings and variables for next book
+          strcpy(outfile,"");
+          strcpy(uinfile,"");
+          strcpy(buffer,"");
+          strcpy(buffer2,"");
+          TopazTrue = 0;
+          strlength = 0;
+
+      }while (! infile.eof() );  // no more books in the file
+    
+    infile.close();    // close books.txt
+      
+
+//    cout << "\n\n\n Do you want to delete all of the books from the input directory?\n\n";  
+//    cout << " DO NOT DELETE IF THESE ARE ONLY COPY OF YOUR BOOKS!!!!\n\n";
+//    cout << " Y or N: ";
+
+
+//    do {  // while not yes or no
+//          YesNo = getch();           // This is a DOS/Windows console command not standard C may not be
+//                                     // Usable under Unix or Mac implementations 
+//             
+//             if((YesNo == 121)||(YesNo == 89))  // y or Y is true
+//               {
+//                 exit = 1;  // valid input exit do while loop
+//                cout << "\n\n";
+//                 system("del .\\input\\*.*");   // delete everything in the input directory      
+//                 cout << "\n\n";
+//               }
+//             if((YesNo == 110)||(YesNo == 78))  // n or N is true
+//               {
+//                 exit = 1;  // valid input exit do while loop      
+//               }
+//       
+//       }while (exit != 1);
+//    cout << "\n\nYesNo = " << YesNo << "\n\n";
+
+    system("PAUSE");
+    
+    system("del books.txt");  // Delete txt file with list of books
+    return EXIT_SUCCESS;
+}
diff --git a/Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle4PCv1_1.exe b/Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle4PCv1_1.exe
new file mode 100644 (file)
index 0000000..d6e3a8f
Binary files /dev/null and b/Kindle_Mobi_Tools/LZskindle4PCv1_1/LZskindle4PCv1_1.exe differ
diff --git a/Kindle_Mobi_Tools/LZskindle4PCv1_1/ReadMe.txt b/Kindle_Mobi_Tools/LZskindle4PCv1_1/ReadMe.txt
new file mode 100644 (file)
index 0000000..40989fd
--- /dev/null
@@ -0,0 +1,27 @@
+Ezskindle4PC.exe 
+
+This executable program makes using skindle easier for people using Windows PC\92s.
+
+I do not know if it will work under any other operating system, however, I have included 
+the source code should anyone want to port it into other operating systems.
+
+To use this program:
+
+1. Copy the ezskindle4PC.exe into the same directory with the skindle files.
+2. Copy the kindle book into the same directory.
+3. double click the EZskindle4PCv1_0.exe file.
+a. A DOS window will open and you will be asked for the name of the file you want to work with.
+4. Type in the book\92s file name.  (it will look something like B000WCTBTA_EBOK.prc)
+5. The program will then check if it is a Topaz file and then create the output file name using the 
+first part of the input file name. It will use \93tpz\94 file extension for Topaz books and will use \93azw\94 
+for non topaz books.  The files with the \93azw\94 format can be converted to other ebook formats using 
+Calibre.  If you want to convert Topaz books to other formats you need to use Topaz tools not skindle.
+6. The program will then create a command line and call the skindle program to process the book and 
+remove the DRM.
+7. The program will pause and allow you to see the result of the skindle process.  
+8. Press any key to close the program.
+
+version 1.1
+Ok
+
+Found a new 32 bit compiler and I think I have worked out the kinks.
index 7e96befb864bef47f6ec65ffd4c9f4a9713bb354..c63ed9c72f5aeb6a45ad8ac8dd207e24b1020e34 100644 (file)
@@ -114,7 +114,7 @@ class MainDialog(Tkinter.Frame):
     def get_mobipath(self):
         mobipath = tkFileDialog.askopenfilename(
             parent=None, title='Select Mobi eBook File',
-            defaultextension='.prc', filetypes=[('Mobi eBook File', '.prc'), ('Mobi eBook File', '.mobi'),
+            defaultextension='.prc', filetypes=[('Mobi eBook File', '.prc'), ('Mobi eBook File', '.azw'),('Mobi eBook File', '.mobi'),
                                                 ('All Files', '.*')])
         if mobipath:
             mobipath = os.path.normpath(mobipath)
index 29e4b30a6f02bde44df9c6a0ef27f0738a640caf..e6076b5869deb2efdf95b9cc44b13a4ef59bb7c0 100644 (file)
@@ -76,6 +76,8 @@ def main(argv=sys.argv):
           print "Kindle 2 Global serial number detected"
       elif serial.startswith("B004"):
           print "Kindle DX serial number detected"
+      elif serial.startswith("B005"):
+          print "Kindle DX International serial number detected"
       else:
           print "Warning: unrecognized serial number. Please recheck input."
           return 1
index 0565356e81e97ad6e43b361b56fc5a89a3ada053..07d5f6f5eca968c5492909043cc4cab7df3f1e15 100644 (file)
@@ -38,8 +38,9 @@
 #         This knowledge leads to a simplification of the test for the 
 #         trailing data byte flags - version 5 and higher AND header size >= 0xE4. 
 #  0.15 - Now outputs 'hearbeat', and is also quicker for long files.
+#  0.16 - And reverts to 'done' not 'done.' at the end for unswindle compatibility.
 
-__version__ = '0.15'
+__version__ = '0.16'
 
 import sys
 import struct
@@ -242,7 +243,7 @@ class DrmStripper:
             if self.num_sections > records+1:
                 new_data += self.data_file[self.sections[records+1][0]:]
             self.data_file = new_data
-            print "done."
+            print "done"
 
     def getResult(self):
         return self.data_file
@@ -255,7 +256,7 @@ if not __name__ == "__main__":
         description         = 'Removes DRM from secure Mobi files'
         supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
         author              = 'The Dark Reverser' # The author of this plugin
-        version             = (0, 1, 5)   # The version number of this plugin
+        version             = (0, 1, 6)   # The version number of this plugin
         file_types          = set(['prc','mobi','azw']) # The file types that this plugin will be applied to
         on_import           = True # Run this plugin during the import
 
index 0565356e81e97ad6e43b361b56fc5a89a3ada053..07d5f6f5eca968c5492909043cc4cab7df3f1e15 100644 (file)
@@ -38,8 +38,9 @@
 #         This knowledge leads to a simplification of the test for the 
 #         trailing data byte flags - version 5 and higher AND header size >= 0xE4. 
 #  0.15 - Now outputs 'hearbeat', and is also quicker for long files.
+#  0.16 - And reverts to 'done' not 'done.' at the end for unswindle compatibility.
 
-__version__ = '0.15'
+__version__ = '0.16'
 
 import sys
 import struct
@@ -242,7 +243,7 @@ class DrmStripper:
             if self.num_sections > records+1:
                 new_data += self.data_file[self.sections[records+1][0]:]
             self.data_file = new_data
-            print "done."
+            print "done"
 
     def getResult(self):
         return self.data_file
@@ -255,7 +256,7 @@ if not __name__ == "__main__":
         description         = 'Removes DRM from secure Mobi files'
         supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
         author              = 'The Dark Reverser' # The author of this plugin
-        version             = (0, 1, 5)   # The version number of this plugin
+        version             = (0, 1, 6)   # The version number of this plugin
         file_types          = set(['prc','mobi','azw']) # The file types that this plugin will be applied to
         on_import           = True # Run this plugin during the import
 
index f04b1b68960f667d3a974e934f406d8b35d01aa6..8eb07715bd3f0542ad6a507e2285f57115e6b814 100644 (file)
@@ -1,13 +1,13 @@
 #! /usr/bin/python
 # -*- coding: utf-8 -*-
 
-# unswindle.pyw, version 6-rc1
-# Copyright © 2009 i♥cabbages
+# unswindle.pyw, version 7
+# Copyright © 2009-2010 i♥cabbages
 
 # Released under the terms of the GNU General Public Licence, version 3 or
 # later.  <http://www.gnu.org/licenses/>
 
-# To run this program install a 32-bit version of Python 2.6 from
+# Before running this program, you must first install Python 2.6 from
 # <http://www.python.org/download/>.  Save this script file as unswindle.pyw.
 # Find and save in the same directory a copy of mobidedrm.py.  Double-click on
 # unswindle.pyw.  It will run Kindle For PC.  Open the book you want to
 #       detect unsupported versions of K4PC
 #   5 - Work with new (20091222) version of K4PC
 #   6 - Detect and just copy DRM-free books
+#   7 - Work with new (20100629) version of K4PC
 
 """
 Decrypt Kindle For PC encrypted Mobipocket books.
 """
 
+from __future__ import with_statement
+
 __license__ = 'GPL v3'
 
 import sys
@@ -622,8 +625,17 @@ class PC1KeyGrabber(object):
             0x0054c9e0: '_get_pc1_pid',
             0x004f8ac9: '_get_book_path',
         },
+        'd791f52dd2ecc68722212d801ad52cb79d1b6fc9': {
+            0x0041724d: '_i_like_wine',
+            0x004bfe3d: '_no_debugger_here',
+            0x005bd9db: '_no_debugger_here',
+            0x00565920: '_get_pc1_pid',
+            0x0050fde9: '_get_book_path',
+        },
     }
 
+    MOBI_EXTENSIONS = set(['.prc', '.pdb', '.mobi', '.azw', '.az1', '.azw1'])
+
     @classmethod
     def supported_version(cls, hexdigest):
         return (hexdigest in cls.HOOKS)
@@ -658,7 +670,8 @@ class PC1KeyGrabber(object):
         path = path.decode('utf-16', 'ignore')
         if u'\0' in path:
             path = path[:path.index(u'\0')]
-        if path[-4:].lower() not in ('.prc', '.pdb', '.mobi'):
+        root, ext = os.path.splitext(path)
+        if ext.lower() not in self.MOBI_EXTENSIONS:
             return
         self.book_path = path
 
@@ -667,7 +680,6 @@ class PC1KeyGrabber(object):
         addr = debugger.read_process_memory(addr, type=ctypes.c_char_p)
         pid = debugger.read_process_memory(addr, 8)
         pid = self._checksum_pid(pid)
-        print pid
         self.book_pid = pid
 
     def _checksum_pid(self, s):
index 0565356e81e97ad6e43b361b56fc5a89a3ada053..07d5f6f5eca968c5492909043cc4cab7df3f1e15 100644 (file)
@@ -38,8 +38,9 @@
 #         This knowledge leads to a simplification of the test for the 
 #         trailing data byte flags - version 5 and higher AND header size >= 0xE4. 
 #  0.15 - Now outputs 'hearbeat', and is also quicker for long files.
+#  0.16 - And reverts to 'done' not 'done.' at the end for unswindle compatibility.
 
-__version__ = '0.15'
+__version__ = '0.16'
 
 import sys
 import struct
@@ -242,7 +243,7 @@ class DrmStripper:
             if self.num_sections > records+1:
                 new_data += self.data_file[self.sections[records+1][0]:]
             self.data_file = new_data
-            print "done."
+            print "done"
 
     def getResult(self):
         return self.data_file
@@ -255,7 +256,7 @@ if not __name__ == "__main__":
         description         = 'Removes DRM from secure Mobi files'
         supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
         author              = 'The Dark Reverser' # The author of this plugin
-        version             = (0, 1, 5)   # The version number of this plugin
+        version             = (0, 1, 6)   # The version number of this plugin
         file_types          = set(['prc','mobi','azw']) # The file types that this plugin will be applied to
         on_import           = True # Run this plugin during the import
 
index 48b7f815fd0d75036816fe5a59214f859daa8323..924d4c90a0dc0492b0caff9d263ff6b43e1ea71b 100644 (file)
@@ -121,7 +121,7 @@ class MainDialog(Tkinter.Frame):
     def get_tpzpath(self):
         tpzpath = tkFileDialog.askopenfilename(
             parent=None, title='Select Topaz File',
-            defaultextension='.prc', filetypes=[('Topaz azw1', '.azw1'), ('Topaz prc', '.prc'),
+            defaultextension='.prc', filetypes=[('Topaz azw', '.azw'),('Topaz azw1', '.azw1'), ('Topaz prc', '.prc'),
                                                 ('All Files', '.*')])
         if tpzpath:
             tpzpath = os.path.normpath(tpzpath)
diff --git a/Topaz_Tools/TopazExtract_KindleV1_iPhone_iPad.pyw b/Topaz_Tools/TopazExtract_KindleV1_iPhone_iPad.pyw
new file mode 100644 (file)
index 0000000..83cb79c
--- /dev/null
@@ -0,0 +1,200 @@
+#!/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='Extract Contents of Topaz eBook to a Directory')
+        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='Topaz eBook input file').grid(row=0, sticky=Tkconstants.E)
+        self.tpzpath = Tkinter.Entry(body, width=50)
+        self.tpzpath.grid(row=0, column=1, sticky=sticky)
+        cwd = os.getcwdu()
+        cwd = cwd.encode('utf-8')
+        self.tpzpath.insert(0, cwd)
+        button = Tkinter.Button(body, text="...", command=self.get_tpzpath)
+        button.grid(row=0, column=2)
+
+        Tkinter.Label(body, text='Output Directory').grid(row=1, sticky=Tkconstants.E)
+        self.outpath = Tkinter.Entry(body, width=50)
+        self.outpath.grid(row=1, column=1, sticky=sticky)
+        cwd = os.getcwdu()
+        cwd = cwd.encode('utf-8')
+        self.outpath.insert(0, cwd)
+        button = Tkinter.Button(body, text="...", command=self.get_outpath)
+        button.grid(row=1, column=2)
+
+        Tkinter.Label(body, text='First 8 characters of PID').grid(row=3, sticky=Tkconstants.E)
+        self.pidnum = Tkinter.StringVar()
+        self.ccinfo = Tkinter.Entry(body, width=10, textvariable=self.pidnum)
+        self.ccinfo.grid(row=3, 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=4, 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' + 'Files successfully extracted\n'
+            if poll != 0:
+                msg = text + '\n\n' + 'Error: File Extraction 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 as a subprocess via pipes and collect stdout
+    def topazrdr(self, infile, outdir, pidnum):
+        # os.putenv('PYTHONUNBUFFERED', '1')
+        pidoption = ' -p "' + pidnum + '" '
+        outoption = ' -o "' + outdir + '" '
+        cmdline = 'python ./lib/cmbtc_dump_nonK4PC.py -v -d ' + pidoption + outoption + '"' + infile + '"'
+        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\cmbtc_dump_nonK4PC.py -v -d ' + pidoption + outoption + '"' + infile + '"'
+            else :
+                cmdline = 'lib\cmbtc_dump_nonK4PC.py -v -d ' + pidoption + outoption + '"' + infile + '"'
+
+        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_tpzpath(self):
+        tpzpath = tkFileDialog.askopenfilename(
+            parent=None, title='Select Topaz File',
+            defaultextension='.prc', filetypes=[('Topaz azw1', '.azw1'), ('Topaz prc', '.prc'),('Topaz azw', '.azw'),
+                                                ('All Files', '.*')])
+        if tpzpath:
+            tpzpath = os.path.normpath(tpzpath)
+            self.tpzpath.delete(0, Tkconstants.END)
+            self.tpzpath.insert(0, tpzpath)
+        return
+
+    def get_outpath(self):
+        cwd = os.getcwdu()
+        cwd = cwd.encode('utf-8')
+        outpath = tkFileDialog.askdirectory(
+            parent=None, title='Directory to Extract Files into',
+            initialdir=cwd, initialfile=None)
+        if outpath:
+            outpath = os.path.normpath(outpath)
+            self.outpath.delete(0, Tkconstants.END)
+            self.outpath.insert(0, outpath)
+        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')
+        tpzpath = self.tpzpath.get()
+        outpath = self.outpath.get()
+        if not tpzpath or not os.path.exists(tpzpath):
+            self.status['text'] = 'Specified Topaz eBook file does not exist'
+            self.sbotton.configure(state='normal')
+            return
+        if not outpath:
+            self.status['text'] = 'No output directory specified'
+            self.sbotton.configure(state='normal')
+            return
+        if not os.path.exists(outpath):
+            os.makedirs(outpath)
+        pidnum = self.pidnum.get()
+        if not pidnum or pidnum == '':
+            self.status['text'] = 'You have not entered a PID '
+            self.sbotton.configure(state='normal')
+            return
+
+        log = 'Command = "python cmbtc_dump_nonK4PC.py"\n'
+        log += 'Topaz Path Path = "'+ tpzpath + '"\n'
+        log += 'Output Directory = "' + outpath + '"\n'
+        log += 'First 8 chars of PID = "' + pidnum + '"\n'
+        log += '\n\n'
+        log += 'Please Wait ...\n'
+        log = log.encode('utf-8')
+        self.stext.insert(Tkconstants.END,log)
+        self.p2 = self.topazrdr(tpzpath, outpath, pidnum)
+
+        # 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('Topaz eBook File Extraction')
+    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 e3f0fe2fde96c4055458e3c66026d90e79040426..d3ccd487c4a8a5932369d32617e5952ef7b61faf 100644 (file)
@@ -245,12 +245,13 @@ class PageParser(object):
 
         '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),
-        'img.h'        : (1, 'scalar_number', 0, 0),
-        'img.w'        : (1, 'scalar_number', 0, 0),
-        'img.src'      : (1, 'scalar_number', 0, 0),
+        'img'           : (1, 'snippets', 1, 0),
+        'img.x'         : (1, 'scalar_number', 0, 0),
+        'img.y'         : (1, 'scalar_number', 0, 0),
+        'img.h'         : (1, 'scalar_number', 0, 0),
+        'img.w'         : (1, 'scalar_number', 0, 0),
+        'img.src'       : (1, 'scalar_number', 0, 0),
+        'img.color_src' : (1, 'scalar_number', 0, 0),
 
         'paragraph'           : (1, 'snippets', 1, 0),
         'paragraph.class'     : (1, 'scalar_text', 0, 0),
@@ -674,6 +675,8 @@ class PageParser(object):
         elif (magic[0:1] == 'p') and (magic[2:9] == '__PAGE_'):
             skip = self.fo.read(2)
             first_token = 'info'
+        elif (magic[0:1] == 'p') and (magic[2:8] == '_PAGE_'):
+            first_token = 'info'
         elif (magic[0:1] == 'g') and (magic[2:9] == '__GLYPH'):
             skip = self.fo.read(3)
             first_token = 'info'
@@ -706,7 +709,10 @@ class PageParser(object):
             else:
                 if self.debug:
                     print "Main Loop:  Unknown value: %x" % v 
-
+                if (v == 0):
+                    if (self.peek(1) == 0x5f):
+                        skip = self.fo.read(1)
+                        first_token = 'info'
 
         # now do snippet injection
         if len(self.snippetList) > 0 :
@@ -795,4 +801,4 @@ def main(argv):
     return xmlpage
 
 if __name__ == '__main__':
-    sys.exit(main(''))
+    sys.exit(main(''))
\ No newline at end of file