diff --git a/Calibre_Plugins/K4MobiDeDRM_plugin/flatxml2html.py b/Calibre_Plugins/K4MobiDeDRM_plugin/flatxml2html.py index 81d93bc..ae2c8dd 100644 --- a/Calibre_Plugins/K4MobiDeDRM_plugin/flatxml2html.py +++ b/Calibre_Plugins/K4MobiDeDRM_plugin/flatxml2html.py @@ -68,7 +68,7 @@ class DocParser(object): ys = [] gdefs = [] - # get path defintions, positions, dimensions for ecah glyph + # get path defintions, positions, dimensions for each glyph # that makes up the image, and find min x and min y to reposition origin minx = -1 miny = -1 @@ -305,6 +305,15 @@ class DocParser(object): lastGlyph = firstglyphList[last] else : lastGlyph = len(gidList) + + # handle case of white sapce paragraphs with no actual glyphs in them + # by reverting to text based paragraph + if firstGlyph >= lastGlyph: + # revert to standard text based paragraph + for wordnum in xrange(first, last): + result.append(('ocr', wordnum)) + return pclass, result + for glyphnum in xrange(firstGlyph, lastGlyph): glyphList.append(glyphnum) # include any extratokens if they exist diff --git a/Calibre_Plugins/eReaderPDB2PML_plugin.zip b/Calibre_Plugins/eReaderPDB2PML_plugin.zip index 7174e72..c852068 100644 Binary files a/Calibre_Plugins/eReaderPDB2PML_plugin.zip and b/Calibre_Plugins/eReaderPDB2PML_plugin.zip differ diff --git a/Calibre_Plugins/eReaderPDB2PML_plugin/erdr2pml.py b/Calibre_Plugins/eReaderPDB2PML_plugin/erdr2pml.py index ce6945d..6df9e13 100644 --- a/Calibre_Plugins/eReaderPDB2PML_plugin/erdr2pml.py +++ b/Calibre_Plugins/eReaderPDB2PML_plugin/erdr2pml.py @@ -57,8 +57,9 @@ # 0.16 - convert to use openssl DES (very very fast) or pure python DES if openssl's libcrypto is not available # 0.17 - added support for pycrypto's DES as well # 0.18 - on Windows try PyCrypto first and OpenSSL next +# 0.19 - Modify the interface to allow use of import -__version__='0.18' +__version__='0.19' class Unbuffered: def __init__(self, stream): @@ -111,12 +112,14 @@ except ImportError: # older Python release import sha sha1 = lambda s: sha.new(s) + import cgi import logging logging.basicConfig() #logging.basicConfig(level=logging.DEBUG) + class Sectionizer(object): def __init__(self, filename, ident): self.contents = file(filename, 'rb').read() @@ -364,7 +367,7 @@ def cleanPML(pml): def convertEreaderToPml(infile, name, cc, outdir): if not os.path.exists(outdir): os.makedirs(outdir) - + bookname = os.path.splitext(os.path.basename(infile))[0] print " Decoding File" sect = Sectionizer(infile, 'PNRdPPrs') er = EreaderProcessor(sect.loadSection, name, cc) @@ -390,6 +393,47 @@ def convertEreaderToPml(infile, name, cc, outdir): # file(os.path.join(outdir, 'bookinfo.txt'),'wb').write(bkinfo) + +def decryptBook(infile, outdir, name, cc, make_pmlz): + if make_pmlz : + # ignore specified outdir, use tempdir instead + outdir = tempfile.mkdtemp() + try: + print "Processing..." + convertEreaderToPml(infile, name, cc, outdir) + if make_pmlz : + import zipfile + import shutil + print " Creating PMLZ file" + zipname = infile[:-4] + '.pmlz' + myZipFile = zipfile.ZipFile(zipname,'w',zipfile.ZIP_STORED, False) + list = os.listdir(outdir) + for file in list: + localname = file + filePath = os.path.join(outdir,file) + if os.path.isfile(filePath): + myZipFile.write(filePath, localname) + elif os.path.isdir(filePath): + imageList = os.listdir(filePath) + localimgdir = os.path.basename(filePath) + for image in imageList: + localname = os.path.join(localimgdir,image) + imagePath = os.path.join(filePath,image) + if os.path.isfile(imagePath): + myZipFile.write(imagePath, localname) + myZipFile.close() + # remove temporary directory + shutil.rmtree(outdir, True) + print 'output is %s' % zipname + else : + print 'output in %s' % outdir + print "done" + except ValueError, e: + print "Error: %s" % e + return 1 + return 0 + + def usage(): print "Converts DRMed eReader books to PML Source" print "Usage:" @@ -404,8 +448,8 @@ def usage(): print " It's enough to enter the last 8 digits of the credit card number" return + def main(argv=None): - global bookname try: opts, args = getopt.getopt(sys.argv[1:], "h", ["make-pmlz"]) except getopt.GetoptError, err: @@ -413,75 +457,27 @@ def main(argv=None): usage() return 1 make_pmlz = False - zipname = None for o, a in opts: if o == "-h": usage() return 0 elif o == "--make-pmlz": make_pmlz = True - zipname = '' print "eRdr2Pml v%s. Copyright (c) 2009 The Dark Reverser" % __version__ if len(args)!=3 and len(args)!=4: usage() return 1 - else: - if len(args)==3: - infile, name, cc = args[0], args[1], args[2] - outdir = infile[:-4] + '_Source' - elif len(args)==4: - infile, outdir, name, cc = args[0], args[1], args[2], args[3] - if make_pmlz : - # ignore specified outdir, use tempdir instead - outdir = tempfile.mkdtemp() - - bookname = os.path.splitext(os.path.basename(infile))[0] - - try: - print "Processing..." - import time - start_time = time.time() - convertEreaderToPml(infile, name, cc, outdir) - - if make_pmlz : - import zipfile - import shutil - print " Creating PMLZ file" - zipname = infile[:-4] + '.pmlz' - myZipFile = zipfile.ZipFile(zipname,'w',zipfile.ZIP_STORED, False) - list = os.listdir(outdir) - for file in list: - localname = file - filePath = os.path.join(outdir,file) - if os.path.isfile(filePath): - myZipFile.write(filePath, localname) - elif os.path.isdir(filePath): - imageList = os.listdir(filePath) - localimgdir = os.path.basename(filePath) - for image in imageList: - localname = os.path.join(localimgdir,image) - imagePath = os.path.join(filePath,image) - if os.path.isfile(imagePath): - myZipFile.write(imagePath, localname) - myZipFile.close() - # remove temporary directory - shutil.rmtree(outdir, True) - - end_time = time.time() - search_time = end_time - start_time - print 'elapsed time: %.2f seconds' % (search_time, ) - if make_pmlz : - print 'output is %s' % zipname - else : - print 'output in %s' % outdir - print "done" - except ValueError, e: - print "Error: %s" % e - return 1 - return 0 + if len(args)==3: + infile, name, cc = args[0], args[1], args[2] + outdir = infile[:-4] + '_Source' + elif len(args)==4: + infile, outdir, name, cc = args[0], args[1], args[2], args[3] + + return decryptBook(infile, outdir, name, cc, make_pmlz) + if __name__ == "__main__": sys.exit(main()) diff --git a/Calibre_Plugins/ignobleepub_plugin.zip b/Calibre_Plugins/ignobleepub_plugin.zip index 5ef5c41..8eba533 100644 Binary files a/Calibre_Plugins/ignobleepub_plugin.zip and b/Calibre_Plugins/ignobleepub_plugin.zip differ diff --git a/Calibre_Plugins/ignobleepub_plugin/ignobleepub_plugin.py b/Calibre_Plugins/ignobleepub_plugin/ignobleepub_plugin.py index 1e79c26..50cb51f 100644 --- a/Calibre_Plugins/ignobleepub_plugin/ignobleepub_plugin.py +++ b/Calibre_Plugins/ignobleepub_plugin/ignobleepub_plugin.py @@ -271,7 +271,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, 3) + version = (0, 1, 4) minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions. file_types = set(['epub']) on_import = True diff --git a/Calibre_Plugins/ignobleepub_plugin/zipfix.py b/Calibre_Plugins/ignobleepub_plugin/zipfix.py index 40c41d2..4c862a7 100644 --- a/Calibre_Plugins/ignobleepub_plugin/zipfix.py +++ b/Calibre_Plugins/ignobleepub_plugin/zipfix.py @@ -81,23 +81,44 @@ 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 - - for i, zinfo in enumerate(self.inzip.infolist()): - data = None - nzinfo = zinfo - - try: - data = self.inzip.read(zinfo) - 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 = zinfo.compress_type - nzinfo.flag_bits = 0 - nzinfo.internal_attr = 0 - self.outzip.writestr(nzinfo,data) + # 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 + + # write the rest of the files + for zinfo in self.inzip.infolist(): + if zinfo.filename != "mimetype": + data = None + 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 = zinfo.compress_type + nzinfo.flag_bits = 0 + nzinfo.internal_attr = 0 + self.outzip.writestr(nzinfo,data) self.bzf.close() self.inzip.close() @@ -111,14 +132,7 @@ def usage(): """ -def main(argv=sys.argv): - if len(argv)!=3: - usage() - return 1 - infile = None - outfile = None - infile = argv[1] - outfile = argv[2] +def repairBook(infile, outfile): if not os.path.exists(infile): print "Error: Input Zip File does not exist" return 1 @@ -130,6 +144,16 @@ def main(argv=sys.argv): print "Error Occurred ", e return 2 + +def main(argv=sys.argv): + if len(argv)!=3: + usage() + return 1 + infile = argv[1] + outfile = argv[2] + return repairBook(infile, outfile) + + if __name__ == '__main__' : sys.exit(main()) diff --git a/Calibre_Plugins/ineptepub_plugin.zip b/Calibre_Plugins/ineptepub_plugin.zip index 4a8f8eb..6c4d6f6 100644 Binary files a/Calibre_Plugins/ineptepub_plugin.zip and b/Calibre_Plugins/ineptepub_plugin.zip differ diff --git a/Calibre_Plugins/ineptepub_plugin/ineptepub_plugin.py b/Calibre_Plugins/ineptepub_plugin/ineptepub_plugin.py index beb924e..e155a3c 100644 --- a/Calibre_Plugins/ineptepub_plugin/ineptepub_plugin.py +++ b/Calibre_Plugins/ineptepub_plugin/ineptepub_plugin.py @@ -371,7 +371,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, 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 diff --git a/Calibre_Plugins/ineptepub_plugin/zipfix.py b/Calibre_Plugins/ineptepub_plugin/zipfix.py index 40c41d2..4c862a7 100644 --- a/Calibre_Plugins/ineptepub_plugin/zipfix.py +++ b/Calibre_Plugins/ineptepub_plugin/zipfix.py @@ -81,23 +81,44 @@ 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 - - for i, zinfo in enumerate(self.inzip.infolist()): - data = None - nzinfo = zinfo - - try: - data = self.inzip.read(zinfo) - 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 = zinfo.compress_type - nzinfo.flag_bits = 0 - nzinfo.internal_attr = 0 - self.outzip.writestr(nzinfo,data) + # 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 + + # write the rest of the files + for zinfo in self.inzip.infolist(): + if zinfo.filename != "mimetype": + data = None + 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 = zinfo.compress_type + nzinfo.flag_bits = 0 + nzinfo.internal_attr = 0 + self.outzip.writestr(nzinfo,data) self.bzf.close() self.inzip.close() @@ -111,14 +132,7 @@ def usage(): """ -def main(argv=sys.argv): - if len(argv)!=3: - usage() - return 1 - infile = None - outfile = None - infile = argv[1] - outfile = argv[2] +def repairBook(infile, outfile): if not os.path.exists(infile): print "Error: Input Zip File does not exist" return 1 @@ -130,6 +144,16 @@ def main(argv=sys.argv): print "Error Occurred ", e return 2 + +def main(argv=sys.argv): + if len(argv)!=3: + usage() + return 1 + infile = argv[1] + outfile = argv[2] + return repairBook(infile, outfile) + + if __name__ == '__main__' : sys.exit(main()) diff --git a/Calibre_Plugins/ineptpdf_plugin.zip b/Calibre_Plugins/ineptpdf_plugin.zip index eccc1b8..d0b8f2a 100644 Binary files a/Calibre_Plugins/ineptpdf_plugin.zip and b/Calibre_Plugins/ineptpdf_plugin.zip differ diff --git a/Calibre_Plugins/k4mobidedrm_plugin.zip b/Calibre_Plugins/k4mobidedrm_plugin.zip index 5ef572b..1efffbb 100644 Binary files a/Calibre_Plugins/k4mobidedrm_plugin.zip and b/Calibre_Plugins/k4mobidedrm_plugin.zip differ diff --git a/Calibre_Plugins/k4mobidedrm_plugin/k4mobidedrm_plugin.py b/Calibre_Plugins/k4mobidedrm_plugin/k4mobidedrm_plugin.py index 880690f..776ca6e 100644 --- a/Calibre_Plugins/k4mobidedrm_plugin/k4mobidedrm_plugin.py +++ b/Calibre_Plugins/k4mobidedrm_plugin/k4mobidedrm_plugin.py @@ -29,7 +29,7 @@ from __future__ import with_statement # and import that ZIP into Calibre using its plugin configuration GUI. -__version__ = '2.1' +__version__ = '2.2' class Unbuffered: def __init__(self, stream): @@ -75,6 +75,7 @@ def zipUpDir(myzip, tempdir,localname): # borrowed from calibre from calibre/src/calibre/__init__.py # added in removal of non-printing chars # and removal of . at start +# convert spaces to underscores def cleanup_name(name): _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') substitute='_' @@ -89,6 +90,7 @@ def cleanup_name(name): # Mac and Unix don't like file names that begin with a full stop if len(one) > 0 and one[0] == '.': one = substitute+one[1:] + one = one.replace(' ','_') return one def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): @@ -248,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, 1) # The version number of this plugin + version = (0, 2, 2) # 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/Calibre_Plugins/k4mobidedrm_plugin/k4mutils.py b/Calibre_Plugins/k4mobidedrm_plugin/k4mutils.py index 1b501ba..5e57701 100644 --- a/Calibre_Plugins/k4mobidedrm_plugin/k4mutils.py +++ b/Calibre_Plugins/k4mobidedrm_plugin/k4mutils.py @@ -189,6 +189,6 @@ def openKindleInfo(kInfoFile=None): raise DrmException('Error: .kindle-info file can not be found') return open(kinfopath,'r') else: - if not os.path.isfile(kinfoFile): + if not os.path.isfile(kInfoFile): raise DrmException('Error: kindle-info file can not be found') return open(kInfoFile, 'r') diff --git a/DeDRM_Macintosh_Application/DeDRM.app.txt b/DeDRM_Macintosh_Application/DeDRM.app.txt index 62ba353..8655915 100644 Binary files a/DeDRM_Macintosh_Application/DeDRM.app.txt and b/DeDRM_Macintosh_Application/DeDRM.app.txt differ diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist index 8d56e56..dba2839 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Info.plist @@ -24,7 +24,7 @@ CFBundleExecutable droplet CFBundleGetInfoString - DeDRM 2.0, Copyright © 2010–2011 by Apprentice Alf. + DeDRM 2.1, Copyright © 2010–2011 by Apprentice Alf and others. CFBundleIconFile droplet CFBundleInfoDictionaryVersion @@ -34,7 +34,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.0 + 2.1 CFBundleSignature dplt LSMinimumSystemVersion @@ -43,14 +43,18 @@ WindowState + dividerCollapsed + + eventLogLevel + -1 name ScriptWindowState positionOfDivider - 709 + 0.0 savedFrame - 1617 62 862 788 1440 -150 1680 1050 + 1578 27 862 788 1440 -150 1680 1050 selectedTabView - result + event log diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/Scripts/main.scpt index 193f382..16313fe 100644 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 diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/cmbtc_v2.2.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/cmbtc_v2.2.py deleted file mode 100644 index 764e38d..0000000 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/cmbtc_v2.2.py +++ /dev/null @@ -1,900 +0,0 @@ -#! /usr/bin/python - -""" - -Comprehensive Mazama Book DRM with Topaz Cryptography V2.2 - ------BEGIN PUBLIC KEY----- -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdBHJ4CNc6DNFCw4MRCw4SWAK6 -M8hYfnNEI0yQmn5Ti+W8biT7EatpauE/5jgQMPBmdNrDr1hbHyHBSP7xeC2qlRWC -B62UCxeu/fpfnvNHDN/wPWWH4jynZ2M6cdcnE5LQ+FfeKqZn7gnG2No1U9h7oOHx -y2/pHuYme7U1TsgSjwIDAQAB ------END PUBLIC KEY----- - -""" - -from __future__ import with_statement - -import csv -import sys -import os -import getopt -import zlib -from struct import pack -from struct import unpack -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 -import _winreg as winreg -import Tkinter -import Tkconstants -import tkMessageBox -import traceback -import hashlib - -MAX_PATH = 255 - -kernel32 = windll.kernel32 -advapi32 = windll.advapi32 -crypt32 = windll.crypt32 - -global kindleDatabase -global bookFile -global bookPayloadOffset -global bookHeaderRecords -global bookMetadata -global bookKey -global command - -# -# Various character maps used to decrypt books. Probably supposed to act as obfuscation -# - -charMap1 = "n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M" -charMap2 = "AaZzB0bYyCc1XxDdW2wEeVv3FfUuG4g-TtHh5SsIiR6rJjQq7KkPpL8lOoMm9Nn_" -charMap3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" -charMap4 = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789" - -# -# Exceptions for all the problems that might happen during the script -# - -class CMBDTCError(Exception): - pass - -class CMBDTCFatal(Exception): - pass - -# -# Stolen stuff -# - -class DataBlob(Structure): - _fields_ = [('cbData', c_uint), - ('pbData', c_void_p)] -DataBlob_p = POINTER(DataBlob) - -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 - 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() - - -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 CMBDTCFatal("Failed to Unprotect Data") - return string_at(outdata.pbData, outdata.cbData) - return CryptUnprotectData -CryptUnprotectData = CryptUnprotectData() - -# -# Returns the MD5 digest of "message" -# - -def MD5(message): - ctx = hashlib.md5() - ctx.update(message) - return ctx.digest() - -# -# Returns the MD5 digest of "message" -# - -def SHA1(message): - ctx = hashlib.sha1() - ctx.update(message) - return ctx.digest() - -# -# Open the book file at path -# - -def openBook(path): - try: - return open(path,'rb') - except: - raise CMBDTCFatal("Could not open book file: " + path) -# -# 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),2): - high = map.find(data[i]) - low = map.find(data[i+1]) - value = (((high * 0x40) ^ 0x80) & 0xFF) + low - result += pack("B",value) - return result - -# -# Locate and open the Kindle.info file (Hopefully in the way it is done in the Kindle application) -# - -def openKindleInfo(): - regkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\") - path = winreg.QueryValueEx(regkey, 'Local AppData')[0] - return open(path+'\\Amazon\\Kindle For PC\\{AMAwzsaPaaZAzmZzZQzgZCAkZ3AjA_AY}\\kindle.info','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 - -# -# Find if the original string for a hashed/encoded string is known. If so return the original string othwise return an empty string. (Totally not optimal) -# - -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 name - -# -# 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 ("--------------------------\n") - else : - print ("Unknown Record") - print getKindleInfoValueForHash(record) - print "\n" -# -# 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) - return CryptUnprotectData(encryptedValue,"") - -# -# 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)) - -# -# Get a 7 bit encoded number from the book file -# - -def bookReadEncodedNumber(): - flag = False - data = ord(bookFile.read(1)) - - if data == 0xFF: - flag = True - data = ord(bookFile.read(1)) - - if data >= 0x80: - datax = (data & 0x7F) - while data >= 0x80 : - data = ord(bookFile.read(1)) - datax = (datax <<7) + (data & 0x7F) - data = datax - - if flag: - data = -data - return data - -# -# Encode a number in 7 bit format -# - -def encodeNumber(number): - result = "" - negative = False - flag = 0 - - if number < 0 : - number = -number + 1 - negative = True - - while True: - byte = number & 0x7F - number = number >> 7 - byte += flag - result += chr(byte) - flag = 0x80 - if number == 0 : - if (byte == 0xFF and negative == False) : - result += chr(0x80) - break - - if negative: - result += chr(0xFF) - - return result[::-1] - -# -# Get a length prefixed string from the file -# - -def bookReadString(): - stringLength = bookReadEncodedNumber() - return unpack(str(stringLength)+"s",bookFile.read(stringLength))[0] - -# -# Returns a length prefixed string -# - -def lengthPrefixString(data): - return encodeNumber(len(data))+data - - -# -# Read and return the data of one header record at the current book file position [[offset,compressedLength,decompressedLength],...] -# - -def bookReadHeaderRecordData(): - nbValues = bookReadEncodedNumber() - values = [] - for i in range (0,nbValues): - values.append([bookReadEncodedNumber(),bookReadEncodedNumber(),bookReadEncodedNumber()]) - return values - -# -# Read and parse one header record at the current book file position and return the associated data [[offset,compressedLength,decompressedLength],...] -# - -def parseTopazHeaderRecord(): - if ord(bookFile.read(1)) != 0x63: - raise CMBDTCFatal("Parse Error : Invalid Header") - - tag = bookReadString() - record = bookReadHeaderRecordData() - return [tag,record] - -# -# Parse the header of a Topaz file, get all the header records and the offset for the payload -# - -def parseTopazHeader(): - global bookHeaderRecords - global bookPayloadOffset - magic = unpack("4s",bookFile.read(4))[0] - - if magic != 'TPZ0': - raise CMBDTCFatal("Parse Error : Invalid Header, not a Topaz file") - - nbRecords = bookReadEncodedNumber() - bookHeaderRecords = {} - - for i in range (0,nbRecords): - result = parseTopazHeaderRecord() - bookHeaderRecords[result[0]] = result[1] - - if ord(bookFile.read(1)) != 0x64 : - raise CMBDTCFatal("Parse Error : Invalid Header") - - bookPayloadOffset = bookFile.tell() - -# -# Get a record in the book payload, given its name and index. If necessary the record is decrypted. The record is not decompressed -# - -def getBookPayloadRecord(name, index): - encrypted = False - - try: - recordOffset = bookHeaderRecords[name][index][0] - except: - raise CMBDTCFatal("Parse Error : Invalid Record, record not found") - - bookFile.seek(bookPayloadOffset + recordOffset) - - tag = bookReadString() - if tag != name : - raise CMBDTCFatal("Parse Error : Invalid Record, record name doesn't match") - - recordIndex = bookReadEncodedNumber() - - if recordIndex < 0 : - encrypted = True - recordIndex = -recordIndex -1 - - if recordIndex != index : - raise CMBDTCFatal("Parse Error : Invalid Record, index doesn't match") - - if bookHeaderRecords[name][index][2] != 0 : - record = bookFile.read(bookHeaderRecords[name][index][2]) - else: - record = bookFile.read(bookHeaderRecords[name][index][1]) - - if encrypted: - ctx = topazCryptoInit(bookKey) - record = topazCryptoDecrypt(record,ctx) - - return record - -# -# Extract, decrypt and decompress a book record indicated by name and index and print it or save it in "filename" -# - -def extractBookPayloadRecord(name, index, filename): - compressed = False - - try: - compressed = bookHeaderRecords[name][index][2] != 0 - record = getBookPayloadRecord(name,index) - except: - print("Could not find record") - - if compressed: - try: - record = zlib.decompress(record) - except: - raise CMBDTCFatal("Could not decompress record") - - if filename != "": - try: - file = open(filename,"wb") - file.write(record) - file.close() - except: - raise CMBDTCFatal("Could not write to destination file") - else: - print(record) - -# -# return next record [key,value] from the book metadata from the current book position -# - -def readMetadataRecord(): - return [bookReadString(),bookReadString()] - -# -# Parse the metadata record from the book payload and return a list of [key,values] -# - -def parseMetadata(): - global bookHeaderRecords - global bookPayloadAddress - global bookMetadata - bookMetadata = {} - bookFile.seek(bookPayloadOffset + bookHeaderRecords["metadata"][0][0]) - tag = bookReadString() - if tag != "metadata" : - raise CMBDTCFatal("Parse Error : Record Names Don't Match") - - flags = ord(bookFile.read(1)) - nbRecords = ord(bookFile.read(1)) - - for i in range (0,nbRecords) : - record =readMetadataRecord() - bookMetadata[record[0]] = record[1] - -# -# 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 - -# -# Context initialisation for the Topaz Crypto -# - -def topazCryptoInit(key): - ctx1 = 0x0CAFFE19E - - for keyChar in key: - keyByte = ord(keyChar) - ctx2 = ctx1 - ctx1 = ((((ctx1 >>2) * (ctx1 >>7))&0xFFFFFFFF) ^ (keyByte * keyByte * 0x0F902007)& 0xFFFFFFFF ) - return [ctx1,ctx2] - -# -# decrypt data with the context prepared by topazCryptoInit() -# - -def topazCryptoDecrypt(data, ctx): - ctx1 = ctx[0] - ctx2 = ctx[1] - - plainText = "" - - for dataChar in data: - dataByte = ord(dataChar) - m = (dataByte ^ ((ctx1 >> 3) &0xFF) ^ ((ctx2<<3) & 0xFF)) &0xFF - ctx2 = ctx1 - ctx1 = (((ctx1 >> 2) * (ctx1 >> 7)) &0xFFFFFFFF) ^((m * m * 0x0F902007) &0xFFFFFFFF) - plainText += chr(m) - - return plainText - -# -# Decrypt a payload record with the PID -# - -def decryptRecord(data,PID): - ctx = topazCryptoInit(PID) - return topazCryptoDecrypt(data, ctx) - -# -# Try to decrypt a dkey record (contains the book PID) -# - -def decryptDkeyRecord(data,PID): - record = decryptRecord(data,PID) - fields = unpack("3sB8sB8s3s",record) - - if fields[0] != "PID" or fields[5] != "pid" : - raise CMBDTCError("Didn't find PID magic numbers in record") - elif fields[1] != 8 or fields[3] != 8 : - raise CMBDTCError("Record didn't contain correct length fields") - elif fields[2] != PID : - raise CMBDTCError("Record didn't contain PID") - - return fields[4] - -# -# Decrypt all the book's dkey records (contain the book PID) -# - -def decryptDkeyRecords(data,PID): - nbKeyRecords = ord(data[0]) - records = [] - data = data[1:] - for i in range (0,nbKeyRecords): - length = ord(data[0]) - try: - key = decryptDkeyRecord(data[1:length+1],PID) - records.append(key) - except CMBDTCError: - pass - data = data[1+length:] - - return records - -# -# Encryption table used to generate the device PID -# - -def generatePidEncryptionTable() : - table = [] - for counter1 in range (0,0x100): - value = counter1 - for counter2 in range (0,8): - if (value & 1 == 0) : - value = value >> 1 - else : - value = value >> 1 - value = value ^ 0xEDB88320 - table.append(value) - return table - -# -# Seed value used to generate the device PID -# - -def generatePidSeed(table,dsn) : - value = 0 - for counter in range (0,4) : - index = (ord(dsn[counter]) ^ value) &0xFF - value = (value >> 8) ^ table[index] - return value - -# -# Generate the device PID -# - -def generateDevicePID(table,dsn,nbRoll): - seed = generatePidSeed(table,dsn) - pidAscii = "" - pid = [(seed >>24) &0xFF,(seed >> 16) &0xff,(seed >> 8) &0xFF,(seed) & 0xFF,(seed>>24) & 0xFF,(seed >> 16) &0xff,(seed >> 8) &0xFF,(seed) & 0xFF] - index = 0 - - for counter in range (0,nbRoll): - pid[index] = pid[index] ^ ord(dsn[counter]) - index = (index+1) %8 - - for counter in range (0,8): - index = ((((pid[counter] >>5) & 3) ^ pid[counter]) & 0x1f) + (pid[counter] >> 7) - pidAscii += charMap4[index] - return pidAscii - -# -# Create decrypted book payload -# - -def createDecryptedPayload(payload): - - # store data to be able to create the header later - headerData= [] - currentOffset = 0 - - # Add social DRM to decrypted files - - try: - data = getKindleInfoValueForKey("kindle.name.info")+":"+ getKindleInfoValueForKey("login") - if payload!= None: - payload.write(lengthPrefixString("sdrm")) - payload.write(encodeNumber(0)) - payload.write(data) - else: - currentOffset += len(lengthPrefixString("sdrm")) - currentOffset += len(encodeNumber(0)) - currentOffset += len(data) - except: - pass - - for headerRecord in bookHeaderRecords: - name = headerRecord - newRecord = [] - - if name != "dkey" : - - for index in range (0,len(bookHeaderRecords[name])) : - offset = currentOffset - - if payload != None: - # write tag - payload.write(lengthPrefixString(name)) - # write data - payload.write(encodeNumber(index)) - payload.write(getBookPayloadRecord(name, index)) - - else : - currentOffset += len(lengthPrefixString(name)) - currentOffset += len(encodeNumber(index)) - currentOffset += len(getBookPayloadRecord(name, index)) - newRecord.append([offset,bookHeaderRecords[name][index][1],bookHeaderRecords[name][index][2]]) - - headerData.append([name,newRecord]) - - - - return headerData - -# -# Create decrypted book -# - -def createDecryptedBook(outputFile): - outputFile = open(outputFile,"wb") - # Write the payload in a temporary file - headerData = createDecryptedPayload(None) - outputFile.write("TPZ0") - outputFile.write(encodeNumber(len(headerData))) - - for header in headerData : - outputFile.write(chr(0x63)) - outputFile.write(lengthPrefixString(header[0])) - outputFile.write(encodeNumber(len(header[1]))) - for numbers in header[1] : - outputFile.write(encodeNumber(numbers[0])) - outputFile.write(encodeNumber(numbers[1])) - outputFile.write(encodeNumber(numbers[2])) - - outputFile.write(chr(0x64)) - createDecryptedPayload(outputFile) - outputFile.close() - -# -# Set the command to execute by the programm according to cmdLine parameters -# - -def setCommand(name) : - global command - if command != "" : - raise CMBDTCFatal("Invalid command line parameters") - else : - command = name - -# -# Program usage -# - -def usage(): - print("\nUsage:") - print("\nCMBDTC.py [options] bookFileName\n") - print("-p Adds a PID to the list of PIDs that are tried to decrypt the book key (can be used several times)") - print("-d Saves a decrypted copy of the book") - print("-r Prints or writes to disk a record indicated in the form name:index (e.g \"img:0\")") - print("-o Output file name to write records and decrypted books") - print("-v Verbose (can be used several times)") - print("-i Prints kindle.info database") - -# -# Main -# - -def main(argv=sys.argv): - global kindleDatabase - global bookMetadata - global bookKey - global bookFile - global command - - progname = os.path.basename(argv[0]) - - verbose = 0 - recordName = "" - recordIndex = 0 - outputFile = "" - PIDs = [] - kindleDatabase = None - command = "" - - - try: - opts, args = getopt.getopt(sys.argv[1:], "vdir:o:p:") - except getopt.GetoptError, err: - # print help information and exit: - print str(err) # will print something like "option -a not recognized" - usage() - sys.exit(2) - - if len(opts) == 0 and len(args) == 0 : - usage() - sys.exit(2) - - for o, a in opts: - if o == "-v": - verbose+=1 - if o == "-i": - setCommand("printInfo") - if o =="-o": - if a == None : - raise CMBDTCFatal("Invalid parameter for -o") - outputFile = a - if o =="-r": - setCommand("printRecord") - try: - recordName,recordIndex = a.split(':') - except: - raise CMBDTCFatal("Invalid parameter for -r") - if o =="-p": - PIDs.append(a) - if o =="-d": - setCommand("doit") - - if command == "" : - raise CMBDTCFatal("No action supplied on command line") - - # - # Read the encrypted database - # - - try: - kindleDatabase = parseKindleInfo() - except Exception, message: - if verbose>0: - print(message) - - if kindleDatabase != None : - if command == "printInfo" : - printKindleInfo() - - # - # Compute the DSN - # - - # Get the Mazama Random number - MazamaRandomNumber = getKindleInfoValueForKey("MazamaRandomNumber") - - # Get the HDD serial - encodedSystemVolumeSerialNumber = encodeHash(str(GetVolumeSerialNumber(GetSystemDirectory().split('\\')[0] + '\\')),charMap1) - - # Get the current user name - encodedUsername = encodeHash(GetUserName(),charMap1) - - # concat, hash and encode - DSN = encode(SHA1(MazamaRandomNumber+encodedSystemVolumeSerialNumber+encodedUsername),charMap1) - - if verbose >1: - print("DSN: " + DSN) - - # - # Compute the device PID - # - - table = generatePidEncryptionTable() - devicePID = generateDevicePID(table,DSN,4) - PIDs.append(devicePID) - - if verbose > 0: - print("Device PID: " + devicePID) - - # - # Open book and parse metadata - # - - if len(args) == 1: - - bookFile = openBook(args[0]) - parseTopazHeader() - parseMetadata() - - # - # Compute book PID - # - - # Get the account token - - if kindleDatabase != None: - kindleAccountToken = getKindleInfoValueForKey("kindle.account.tokens") - - if verbose >1: - print("Account Token: " + kindleAccountToken) - - keysRecord = bookMetadata["keys"] - keysRecordRecord = bookMetadata[keysRecord] - - pidHash = SHA1(DSN+kindleAccountToken+keysRecord+keysRecordRecord) - - bookPID = encodePID(pidHash) - PIDs.append(bookPID) - - if verbose > 0: - print ("Book PID: " + bookPID ) - - # - # Decrypt book key - # - - dkey = getBookPayloadRecord('dkey', 0) - - bookKeys = [] - for PID in PIDs : - bookKeys+=decryptDkeyRecords(dkey,PID) - - if len(bookKeys) == 0 : - if verbose > 0 : - print ("Book key could not be found. Maybe this book is not registered with this device.") - else : - bookKey = bookKeys[0] - if verbose > 0: - print("Book key: " + bookKey.encode('hex')) - - - - if command == "printRecord" : - extractBookPayloadRecord(recordName,int(recordIndex),outputFile) - if outputFile != "" and verbose>0 : - print("Wrote record to file: "+outputFile) - elif command == "doit" : - if outputFile!="" : - createDecryptedBook(outputFile) - if verbose >0 : - print ("Decrypted book saved. Don't pirate!") - elif verbose > 0: - print("Output file name was not supplied.") - - return 0 - -if __name__ == '__main__': - sys.exit(main()) - diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf index 0f8be61..33192ea 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/description.rtfd/TXT.rtf @@ -1,4 +1,4 @@ -{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540 +{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350 {\fonttbl} {\colortbl;\red255\green255\blue255;} } \ No newline at end of file diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py index 81d93bc..ae2c8dd 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/flatxml2html.py @@ -68,7 +68,7 @@ class DocParser(object): ys = [] gdefs = [] - # get path defintions, positions, dimensions for ecah glyph + # get path defintions, positions, dimensions for each glyph # that makes up the image, and find min x and min y to reposition origin minx = -1 miny = -1 @@ -305,6 +305,15 @@ class DocParser(object): lastGlyph = firstglyphList[last] else : lastGlyph = len(gidList) + + # handle case of white sapce paragraphs with no actual glyphs in them + # by reverting to text based paragraph + if firstGlyph >= lastGlyph: + # revert to standard text based paragraph + for wordnum in xrange(first, last): + result.append(('ocr', wordnum)) + return pclass, result + for glyphnum in xrange(firstGlyph, lastGlyph): glyphList.append(glyphnum) # include any extratokens if they exist diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/genxml.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/genxml.py deleted file mode 100644 index be542f0..0000000 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/genxml.py +++ /dev/null @@ -1,145 +0,0 @@ -#! /usr/bin/python -# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab -# For use with Topaz Scripts Version 2.6 - -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, getopt - -# local routines -import convert2xml -import flatxml2html -import decode_meta - - -def usage(): - print 'Usage: ' - print ' ' - print ' genxml.py dict0000.dat unencryptedBookDir' - print ' ' - - - -def main(argv): - bookDir = '' - - if len(argv) == 0: - argv = sys.argv - - try: - opts, args = getopt.getopt(argv[1:], "h:") - - except getopt.GetoptError, err: - print str(err) - usage() - sys.exit(1) - - if len(opts) == 0 and len(args) == 0 : - usage() - sys.exit(1) - - for o, a in opts: - if o =="-h": - usage() - sys.exit(0) - - bookDir = args[0] - - if not os.path.exists(bookDir) : - print "Can not find directory with unencrypted book" - sys.exit(1) - - dictFile = os.path.join(bookDir,'dict0000.dat') - if not os.path.exists(dictFile) : - print "Can not find dict0000.dat file" - sys.exit(1) - - pageDir = os.path.join(bookDir,'page') - if not os.path.exists(pageDir) : - print "Can not find page directory in unencrypted book" - sys.exit(1) - - glyphsDir = os.path.join(bookDir,'glyphs') - if not os.path.exists(glyphsDir) : - print "Can not find glyphs directory in unencrypted book" - sys.exit(1) - - otherFile = os.path.join(bookDir,'other0000.dat') - if not os.path.exists(otherFile) : - print "Can not find other0000.dat in unencrypted book" - sys.exit(1) - - metaFile = os.path.join(bookDir,'metadata0000.dat') - if not os.path.exists(metaFile) : - print "Can not find metadata0000.dat in unencrypted book" - sys.exit(1) - - xmlDir = os.path.join(bookDir,'xml') - if not os.path.exists(xmlDir): - os.makedirs(xmlDir) - - - print 'Processing ... ' - - print ' ', 'metadata0000.dat' - fname = os.path.join(bookDir,'metadata0000.dat') - xname = os.path.join(xmlDir, 'metadata.txt') - metastr = decode_meta.getMetaData(fname) - file(xname, 'wb').write(metastr) - - print ' ', 'other0000.dat' - fname = os.path.join(bookDir,'other0000.dat') - xname = os.path.join(xmlDir, 'stylesheet.xml') - pargv=[] - pargv.append('convert2xml.py') - pargv.append(dictFile) - pargv.append(fname) - xmlstr = convert2xml.main(pargv) - file(xname, 'wb').write(xmlstr) - - filenames = os.listdir(pageDir) - filenames = sorted(filenames) - - for filename in filenames: - print ' ', filename - fname = os.path.join(pageDir,filename) - xname = os.path.join(xmlDir, filename.replace('.dat','.xml')) - pargv=[] - pargv.append('convert2xml.py') - pargv.append(dictFile) - pargv.append(fname) - xmlstr = convert2xml.main(pargv) - file(xname, 'wb').write(xmlstr) - - filenames = os.listdir(glyphsDir) - filenames = sorted(filenames) - - for filename in filenames: - print ' ', filename - fname = os.path.join(glyphsDir,filename) - xname = os.path.join(xmlDir, filename.replace('.dat','.xml')) - pargv=[] - pargv.append('convert2xml.py') - pargv.append(dictFile) - pargv.append(fname) - xmlstr = convert2xml.main(pargv) - file(xname, 'wb').write(xmlstr) - - - print 'Processing Complete' - - return 0 - -if __name__ == '__main__': - sys.exit(main('')) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.pyw b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py similarity index 98% rename from DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.pyw rename to DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py index 0afc2bc..a7c48c9 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.pyw +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignobleepub.py @@ -1,6 +1,8 @@ #! /usr/bin/python -# ignobleepub.pyw, version 3.3 +from __future__ import with_statement + +# ignobleepub.pyw, version 3.4 # To run this program install Python 2.6 from # and OpenSSL or PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto @@ -14,10 +16,9 @@ # 3.1 - Allow Windows versions of libcrypto to be found # 3.2 - add support for encoding to 'utf-8' when building up list of files to cecrypt from encryption.xml # 3.3 - On Windows try PyCrypto first and OpenSSL next +# 3.4 - Modify interace to allow use with import -from __future__ import with_statement - __license__ = 'GPL v3' import sys @@ -170,49 +171,6 @@ class Decryptor(object): return data - -def cli_main(argv=sys.argv): - progname = os.path.basename(argv[0]) - if AES is None: - 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,) - return 1 - keypath, inpath, outpath = argv[1:] - with open(keypath, 'rb') as f: - keyb64 = f.read() - key = keyb64.decode('base64')[:16] - # aes = AES.new(key, AES.MODE_CBC) - aes = AES(key) - - with closing(ZipFile(open(inpath, 'rb'))) as inf: - namelist = set(inf.namelist()) - if 'META-INF/rights.xml' not in namelist or \ - 'META-INF/encryption.xml' not in namelist: - raise IGNOBLEError('%s: not an B&N ADEPT EPUB' % (inpath,)) - for name in META_NAMES: - namelist.remove(name) - rights = etree.fromstring(inf.read('META-INF/rights.xml')) - adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag) - expr = './/%s' % (adept('encryptedKey'),) - bookkey = ''.join(rights.findtext(expr)) - bookkey = aes.decrypt(bookkey.decode('base64')) - bookkey = bookkey[:-ord(bookkey[-1])] - encryption = inf.read('META-INF/encryption.xml') - decryptor = Decryptor(bookkey[-16:], encryption) - kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) - with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: - zi = ZipInfo('mimetype', compress_type=ZIP_STORED) - outf.writestr(zi, inf.read('mimetype')) - for path in namelist: - data = inf.read(path) - outf.writestr(path, decryptor.decrypt(path, data)) - return 0 - - class DecryptionDialog(Tkinter.Frame): def __init__(self, root): Tkinter.Frame.__init__(self, root, border=5) @@ -308,6 +266,53 @@ class DecryptionDialog(Tkinter.Frame): return self.status['text'] = 'File successfully decrypted' + +def decryptBook(keypath, inpath, outpath): + with open(keypath, 'rb') as f: + keyb64 = f.read() + key = keyb64.decode('base64')[:16] + # aes = AES.new(key, AES.MODE_CBC) + aes = AES(key) + + with closing(ZipFile(open(inpath, 'rb'))) as inf: + namelist = set(inf.namelist()) + if 'META-INF/rights.xml' not in namelist or \ + 'META-INF/encryption.xml' not in namelist: + raise IGNOBLEError('%s: not an B&N ADEPT EPUB' % (inpath,)) + for name in META_NAMES: + namelist.remove(name) + rights = etree.fromstring(inf.read('META-INF/rights.xml')) + adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag) + expr = './/%s' % (adept('encryptedKey'),) + bookkey = ''.join(rights.findtext(expr)) + bookkey = aes.decrypt(bookkey.decode('base64')) + bookkey = bookkey[:-ord(bookkey[-1])] + encryption = inf.read('META-INF/encryption.xml') + decryptor = Decryptor(bookkey[-16:], encryption) + kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) + with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: + zi = ZipInfo('mimetype', compress_type=ZIP_STORED) + outf.writestr(zi, inf.read('mimetype')) + for path in namelist: + data = inf.read(path) + outf.writestr(path, decryptor.decrypt(path, data)) + return 0 + + +def cli_main(argv=sys.argv): + progname = os.path.basename(argv[0]) + if AES is None: + 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,) + return 1 + keypath, inpath, outpath = argv[1:] + return decryptBook(keypath, inpath, outpath) + + def gui_main(): root = Tkinter.Tk() if AES is None: @@ -324,6 +329,7 @@ def gui_main(): root.mainloop() return 0 + if __name__ == '__main__': if len(sys.argv) > 1: sys.exit(cli_main()) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.pyw b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py similarity index 98% rename from DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.pyw rename to DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py index b2607ea..cdedc48 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.pyw +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ignoblekeygen.py @@ -1,6 +1,8 @@ #! /usr/bin/python -# ignoblekeygen.pyw, version 2.2 +from __future__ import with_statement + +# ignoblekeygen.pyw, version 2.3 # To run this program install Python 2.6 from # and OpenSSL or PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto @@ -12,12 +14,12 @@ # 2 - Add OS X support by using OpenSSL when available (taken/modified from ineptepub v5) # 2.1 - Allow Windows versions of libcrypto to be found # 2.2 - On Windows try PyCrypto first and then OpenSSL next +# 2.3 - Modify interface to allow use of import + """ Generate Barnes & Noble EPUB user key from name and credit card number. """ -from __future__ import with_statement - __license__ = 'GPL v3' import sys @@ -120,6 +122,7 @@ AES = _load_crypto() def normalize_name(name): return ''.join(x for x in name.lower() if x != ' ') + def generate_keyfile(name, ccn, outpath): name = normalize_name(name) + '\x00' ccn = ccn + '\x00' @@ -133,19 +136,6 @@ def generate_keyfile(name, ccn, outpath): f.write(userkey.encode('base64')) return userkey -def cli_main(argv=sys.argv): - progname = os.path.basename(argv[0]) - if AES is None: - 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 NAME CC# OUTFILE" % (progname,) - return 1 - name, ccn, outpath = argv[1:] - generate_keyfile(name, ccn, outpath) - return 0 class DecryptionDialog(Tkinter.Frame): def __init__(self, root): @@ -211,6 +201,22 @@ class DecryptionDialog(Tkinter.Frame): return self.status['text'] = 'Keyfile successfully generated' + +def cli_main(argv=sys.argv): + progname = os.path.basename(argv[0]) + if AES is None: + 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 NAME CC# OUTFILE" % (progname,) + return 1 + name, ccn, outpath = argv[1:] + generate_keyfile(name, ccn, outpath) + return 0 + + def gui_main(): root = Tkinter.Tk() if AES is None: diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.pyw b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py similarity index 98% rename from DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.pyw rename to DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py index 9d95720..48a75f9 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.pyw +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptepub.py @@ -1,7 +1,9 @@ #! /usr/bin/python # -*- coding: utf-8 -*- -# ineptepub.pyw, version 5.5 +from __future__ import with_statement + +# ineptepub.pyw, version 5.6 # Copyright © 2009-2010 i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 or @@ -27,13 +29,11 @@ # 5.3 - add support for OpenSSL on Windows, fix bug with some versions of libcrypto 0.9.8 prior to path level o # 5.4 - add support for encoding to 'utf-8' when building up list of files to decrypt from encryption.xml # 5.5 - On Windows try PyCrypto first, OpenSSL next - +# 5.6 - Modify interface to allow use with import """ Decrypt Adobe ADEPT-encrypted EPUB books. """ -from __future__ import with_statement - __license__ = 'GPL v3' import sys @@ -312,45 +312,6 @@ class Decryptor(object): data = self.decompress(data) return data -def cli_main(argv=sys.argv): - progname = os.path.basename(argv[0]) - if AES is None: - 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,) - return 1 - keypath, inpath, outpath = argv[1:] - with open(keypath, 'rb') as f: - keyder = f.read() - rsa = RSA(keyder) - with closing(ZipFile(open(inpath, 'rb'))) as inf: - namelist = set(inf.namelist()) - if 'META-INF/rights.xml' not in namelist or \ - 'META-INF/encryption.xml' not in namelist: - raise ADEPTError('%s: not an ADEPT EPUB' % (inpath,)) - for name in META_NAMES: - namelist.remove(name) - rights = etree.fromstring(inf.read('META-INF/rights.xml')) - adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag) - expr = './/%s' % (adept('encryptedKey'),) - bookkey = ''.join(rights.findtext(expr)) - bookkey = rsa.decrypt(bookkey.decode('base64')) - # Padded as per RSAES-PKCS1-v1_5 - if bookkey[-17] != '\x00': - raise ADEPTError('problem decrypting session key') - encryption = inf.read('META-INF/encryption.xml') - decryptor = Decryptor(bookkey[-16:], encryption) - kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) - with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: - zi = ZipInfo('mimetype', compress_type=ZIP_STORED) - outf.writestr(zi, inf.read('mimetype')) - for path in namelist: - data = inf.read(path) - outf.writestr(path, decryptor.decrypt(path, data)) - return 0 class DecryptionDialog(Tkinter.Frame): def __init__(self, root): @@ -446,6 +407,52 @@ class DecryptionDialog(Tkinter.Frame): return self.status['text'] = 'File successfully decrypted' + +def decryptBook(keypath, inpath, outpath): + with open(keypath, 'rb') as f: + keyder = f.read() + rsa = RSA(keyder) + with closing(ZipFile(open(inpath, 'rb'))) as inf: + namelist = set(inf.namelist()) + if 'META-INF/rights.xml' not in namelist or \ + 'META-INF/encryption.xml' not in namelist: + raise ADEPTError('%s: not an ADEPT EPUB' % (inpath,)) + for name in META_NAMES: + namelist.remove(name) + rights = etree.fromstring(inf.read('META-INF/rights.xml')) + adept = lambda tag: '{%s}%s' % (NSMAP['adept'], tag) + expr = './/%s' % (adept('encryptedKey'),) + bookkey = ''.join(rights.findtext(expr)) + bookkey = rsa.decrypt(bookkey.decode('base64')) + # Padded as per RSAES-PKCS1-v1_5 + if bookkey[-17] != '\x00': + raise ADEPTError('problem decrypting session key') + encryption = inf.read('META-INF/encryption.xml') + decryptor = Decryptor(bookkey[-16:], encryption) + kwds = dict(compression=ZIP_DEFLATED, allowZip64=False) + with closing(ZipFile(open(outpath, 'wb'), 'w', **kwds)) as outf: + zi = ZipInfo('mimetype', compress_type=ZIP_STORED) + outf.writestr(zi, inf.read('mimetype')) + for path in namelist: + data = inf.read(path) + outf.writestr(path, decryptor.decrypt(path, data)) + return 0 + + +def cli_main(argv=sys.argv): + progname = os.path.basename(argv[0]) + if AES is None: + 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,) + return 1 + keypath, inpath, outpath = argv[1:] + return decryptBook(keypath, inpath, outpath) + + def gui_main(): root = Tkinter.Tk() if AES is None: diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.pyw b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.py similarity index 99% rename from DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.pyw rename to DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.py index fd90508..8eab14f 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.pyw +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptkey.py @@ -1,7 +1,9 @@ #! /usr/bin/python # -*- coding: utf-8 -*- -# ineptkey.pyw, version 5.3 +from __future__ import with_statement + +# ineptkey.pyw, version 5.4 # Copyright © 2009-2010 i♥cabbages # Released under the terms of the GNU General Public Licence, version 3 or @@ -33,13 +35,12 @@ # 5.1 - add support for using OpenSSL on Windows in place of PyCrypto # 5.2 - added support for output of key to a particular file # 5.3 - On Windows try PyCrypto first, OpenSSL next +# 5.4 - Modify interface to allow use of import """ Retrieve Adobe ADEPT user key. """ -from __future__ import with_statement - __license__ = 'GPL v3' import sys @@ -415,10 +416,11 @@ class ExceptionDialog(Tkinter.Frame): label.pack(fill=Tkconstants.X, expand=0) self.text = Tkinter.Text(self) self.text.pack(fill=Tkconstants.BOTH, expand=1) + self.text.insert(Tkconstants.END, text) -def cli_main(argv=sys.argv): - keypath = argv[1] + +def extractKeyfile(keypath): try: success = retrieve_key(keypath) except ADEPTError, e: @@ -431,6 +433,12 @@ def cli_main(argv=sys.argv): return 1 return 0 + +def cli_main(argv=sys.argv): + keypath = argv[1] + return extractKeyfile(keypath) + + def main(argv=sys.argv): root = Tkinter.Tk() root.withdraw() diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.pyw b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py similarity index 99% rename from DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.pyw rename to DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py index d73e069..ccdd9e4 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.pyw +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/ineptpdf.py @@ -1,6 +1,8 @@ #! /usr/bin/env python # ineptpdf.pyw, version 7.7 +from __future__ import with_statement + # To run this program install Python 2.6 from http://www.python.org/download/ # and OpenSSL (already installed on Mac OS X and Linux) OR # PyCrypto from http://www.voidspace.org.uk/python/modules.shtml#pycrypto @@ -30,13 +32,12 @@ # fixed minor typos # 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 """ Decrypts Adobe ADEPT-encrypted PDF files. """ -from __future__ import with_statement - __license__ = 'GPL v3' import sys @@ -2076,25 +2077,6 @@ class PDFSerializer(object): self.write('\n') self.write('endobj\n') -def cli_main(argv=sys.argv): - progname = os.path.basename(argv[0]) - if RSA is None: - 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,) - return 1 - keypath, inpath, outpath = argv[1:] - with open(inpath, 'rb') as inf: - serializer = PDFSerializer(inf, keypath) - # hope this will fix the 'bad file descriptor' problem - with open(outpath, 'wb') as outf: - # help construct to make sure the method runs to the end - serializer.dump(outf) - return 0 - class DecryptionDialog(Tkinter.Frame): def __init__(self, root): @@ -2198,6 +2180,31 @@ class DecryptionDialog(Tkinter.Frame): 'Close this window or decrypt another pdf file.' return + +def decryptBook(keypath, inpath, outpath): + with open(inpath, 'rb') as inf: + serializer = PDFSerializer(inf, keypath) + # hope this will fix the 'bad file descriptor' problem + with open(outpath, 'wb') as outf: + # help construct to make sure the method runs to the end + serializer.dump(outf) + return 0 + + +def cli_main(argv=sys.argv): + progname = os.path.basename(argv[0]) + if RSA is None: + 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,) + return 1 + keypath, inpath, outpath = argv[1:] + return decryptBook(keypath, inpath, outpath) + + def gui_main(): root = Tkinter.Tk() if RSA is None: diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py index 7088c06..776ca6e 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mobidedrm.py @@ -29,7 +29,7 @@ from __future__ import with_statement # and import that ZIP into Calibre using its plugin configuration GUI. -__version__ = '2.1' +__version__ = '2.2' class Unbuffered: def __init__(self, stream): @@ -75,21 +75,23 @@ def zipUpDir(myzip, tempdir,localname): # borrowed from calibre from calibre/src/calibre/__init__.py # added in removal of non-printing chars # and removal of . at start +# convert spaces to underscores def cleanup_name(name): - _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') - substitute='_' - one = ''.join(char for char in name if char in string.printable) - one = _filename_sanitize.sub(substitute, one) - one = re.sub(r'\s', ' ', one).strip() - one = re.sub(r'^\.+$', '_', one) - one = one.replace('..', substitute) - # Windows doesn't like path components that end with a period - if one.endswith('.'): - one = one[:-1]+substitute - # Mac and Unix don't like file names that begin with a full stop - if len(one) > 0 and one[0] == '.': - one = substitute+one[1:] - return one + _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') + substitute='_' + one = ''.join(char for char in name if char in string.printable) + one = _filename_sanitize.sub(substitute, one) + one = re.sub(r'\s', ' ', one).strip() + one = re.sub(r'^\.+$', '_', one) + one = one.replace('..', substitute) + # Windows doesn't like path components that end with a period + if one.endswith('.'): + one = one[:-1]+substitute + # Mac and Unix don't like file names that begin with a full stop + if len(one) > 0 and one[0] == '.': + one = substitute+one[1:] + one = one.replace(' ','_') + return one def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): import mobidedrm @@ -119,7 +121,7 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): filenametitle = cleanup_name(title) outfilename = bookname if len(bookname)>4 and len(filenametitle)>4 and bookname[:4] != filenametitle[:4]: - outfilename = outfilename + "_"+filenametitle + outfilename = outfilename + "_" + filenametitle # build pid list md1, md2 = mb.getPIDMetaInfo() @@ -134,15 +136,17 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): except mobidedrm.DrmException, e: print "Error: " + str(e) + "\nDRM Removal Failed.\n" return 1 - except topazextract.TpzDRMError, e: - print str(e) - print " Creating DeBug Full Zip Archive of Book" - zipname = os.path.join(outdir, bookname + '_debug' + '.zip') - myzip = zipfile.ZipFile(zipname,'w',zipfile.ZIP_DEFLATED, False) - zipUpDir(myzip, tempdir, '') - myzip.close() - shutil.rmtree(tempdir, True) - return 1 + except Exception, e: + if not mobi: + print "Error: " + str(e) + "\nDRM Removal Failed.\n" + print " Creating DeBug Full Zip Archive of Book" + zipname = os.path.join(outdir, bookname + '_debug' + '.zip') + myzip = zipfile.ZipFile(zipname,'w',zipfile.ZIP_DEFLATED, False) + zipUpDir(myzip, tempdir, '') + myzip.close() + shutil.rmtree(tempdir, True) + return 1 + pass if mobi: outfile = os.path.join(outdir,outfilename + '_nodrm' + '.mobi') @@ -198,7 +202,7 @@ def main(argv=sys.argv): pids = [] print ('K4MobiDeDrm v%(__version__)s ' - 'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals()) + 'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals()) print ' ' try: @@ -246,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, 1) # The version number of this plugin + version = (0, 2, 2) # 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 @@ -272,15 +276,15 @@ if not __name__ == "__main__" and inCalibre: for customvalue in customvalues: customvalue = str(customvalue) customvalue = customvalue.strip() - if len(customvalue) == 10 or len(customvalue) == 8: + if len(customvalue) == 10 or len(customvalue) == 8: pids.append(customvalue) - else : + else : if len(customvalue) == 16 and customvalue[0] == 'B': serials.append(customvalue) else: print "%s is not a valid Kindle serial number or PID." % str(customvalue) - - # Load any kindle info files (*.info) included Calibre's config directory. + + # Load any kindle info files (*.info) included Calibre's config directory. try: # Find Calibre's configuration directory. confpath = os.path.split(os.path.split(self.plugin_path)[0])[0] @@ -288,7 +292,7 @@ if not __name__ == "__main__" and inCalibre: files = os.listdir(confpath) filefilter = re.compile("\.info$", re.IGNORECASE) files = filter(filefilter.search, files) - + if files: for filename in files: fpath = os.path.join(confpath, filename) diff --git a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mutils.py b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mutils.py index 1b501ba..5e57701 100644 --- a/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mutils.py +++ b/DeDRM_Macintosh_Application/DeDRM.app/Contents/Resources/k4mutils.py @@ -189,6 +189,6 @@ def openKindleInfo(kInfoFile=None): raise DrmException('Error: .kindle-info file can not be found') return open(kinfopath,'r') else: - if not os.path.isfile(kinfoFile): + if not os.path.isfile(kInfoFile): raise DrmException('Error: kindle-info file can not be found') return open(kInfoFile, 'r') diff --git a/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/DeDRM_app.pyw b/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/DeDRM_app.pyw index d3d6bda..a319631 100644 --- a/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/DeDRM_app.pyw +++ b/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/DeDRM_app.pyw @@ -2,8 +2,8 @@ # vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab import sys -sys.path.append('lib') import os, os.path +sys.path.append(sys.path[0]+os.sep+'lib') import shutil import Tkinter from Tkinter import * @@ -22,10 +22,11 @@ class DrmException(Exception): pass class MainApp(Tk): - def __init__(self, dnd=False, filenames=[]): + def __init__(self, apphome, dnd=False, filenames=[]): Tk.__init__(self) self.withdraw() self.dnd = dnd + self.apphome = apphome # preference settings # [dictionary key, file in preferences directory where info is stored] description = [ ['pids' , 'pidlist.txt' ], @@ -312,6 +313,7 @@ class ConvDialog(Toplevel): self.protocol("WM_DELETE_WINDOW", self.withdraw) self.title("DeDRM Processing") self.master = master + self.apphome = self.master.apphome self.prefs_array = prefs_array self.filenames = filenames self.interval = 50 @@ -328,11 +330,11 @@ class ConvDialog(Toplevel): body.grid_columnconfigure(1, weight=2) Tkinter.Label(body, text='Activity Bar').grid(row=0, sticky=Tkconstants.E) - self.bar = ActivityBar(body, length=50, height=15, barwidth=5) + self.bar = ActivityBar(body, length=80, height=15, barwidth=5) self.bar.grid(row=0, column=1, sticky=sticky) msg1 = '' - self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=4, width=50, wrap=Tkconstants.WORD) + self.stext = ScrolledText(body, bd=5, relief=Tkconstants.RIDGE, height=4, width=80, wrap=Tkconstants.WORD) self.stext.grid(row=2, column=0, columnspan=2,sticky=sticky) self.stext.insert(Tkconstants.END,msg1) @@ -435,7 +437,6 @@ class ConvDialog(Toplevel): if poll != 0: msg = 'Failed\n' text = self.p2.read() - text = self.p2.read() text += self.p2.readerr() msg += text msg += '\n' @@ -451,42 +452,43 @@ class ConvDialog(Toplevel): return def decrypt_ebook(self, infile, outdir, rscpath): + apphome = self.apphome rv = 1 name, ext = os.path.splitext(os.path.basename(infile)) ext = ext.lower() if ext == '.epub': outfile = os.path.join(outdir, name + '_nodrm.epub') - self.p2 = processEPUB(infile, outfile, rscpath) + self.p2 = processEPUB(apphome, infile, outfile, rscpath) return 0 if ext == '.pdb': - self.p2 = processPDB(infile, outdir, rscpath) + self.p2 = processPDB(apphome, infile, outdir, rscpath) return 0 if ext in ['.azw', '.azw1', '.prc', '.mobi', '.tpz']: - self.p2 = processK4MOBI(infile, outdir, rscpath) + self.p2 = processK4MOBI(apphome, infile, outdir, rscpath) return 0 if ext == '.pdf': outfile = os.path.join(outdir, name + '_nodrm.pdf') - self.p2 = processPDF(infile, outfile, rscpath) + self.p2 = processPDF(apphome, infile, outfile, rscpath) return 0 return rv # run as a subprocess via pipes and collect stdout, stderr, and return value -def runit(ncmd, nparms): - cmdline = 'python ' + ncmd +def runit(apphome, ncmd, nparms): + cmdline = 'python ' + '"' + os.path.join(apphome, ncmd) + '" ' if sys.platform.startswith('win'): search_path = os.environ['PATH'] search_path = search_path.lower() if search_path.find('python') < 0: # if no python hope that win registry finds what is associated with py extension - cmdline = ncmd + cmdline = '"' + os.path.join(apphome, ncmd) + '" ' cmdline += nparms cmdline = cmdline.encode(sys.getfilesystemencoding()) p2 = subasyncio.Process(cmdline, shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=False) return p2 -def processK4MOBI(infile, outdir, rscpath): - cmd = '"' + os.path.join('lib','k4mobidedrm.py') + '" ' +def processK4MOBI(apphome, infile, outdir, rscpath): + cmd = os.path.join('lib','k4mobidedrm.py') parms = '' pidnums = '' pidspath = os.path.join(rscpath,'pidlist.txt') @@ -511,30 +513,33 @@ def processK4MOBI(infile, outdir, rscpath): dpath = os.path.join(rscpath,filename) parms += '-k "' + dpath + '" ' parms += '"' + infile +'" "' + outdir + '"' - p2 = runit(cmd, parms) + p2 = runit(apphome, cmd, parms) return p2 -def processPDF(infile, outfile, rscpath): - cmd = '"' + os.path.join('lib','decryptpdf.py') + '" ' +def processPDF(apphome, infile, outfile, rscpath): + cmd = os.path.join('lib','decryptpdf.py') parms = '"' + infile + '" "' + outfile + '" "' + rscpath + '"' - p2 = runit(cmd, parms) + p2 = runit(apphome, cmd, parms) return p2 -def processEPUB(infile, outfile, rscpath): +def processEPUB(apphome, infile, outfile, rscpath): # invoke routine to check both Adept and Barnes and Noble - cmd = '"' + os.path.join('lib','decryptepub.py') + '" ' + cmd = os.path.join('lib','decryptepub.py') parms = '"' + infile + '" "' + outfile + '" "' + rscpath + '"' - p2 = runit(cmd, parms) + p2 = runit(apphome, cmd, parms) return p2 -def processPDB(infile, outdir, rscpath): - cmd = '"' + os.path.join('lib','decryptpdb.py') + '" ' +def processPDB(apphome, infile, outdir, rscpath): + cmd = os.path.join('lib','decryptpdb.py') parms = '"' + infile + '" "' + outdir + '" "' + rscpath + '"' - p2 = runit(cmd, parms) + p2 = runit(apphome, cmd, parms) return p2 def main(argv=sys.argv): + apphome = os.path.dirname(sys.argv[0]) + apphome = os.path.abspath(apphome) + # windows may pass a spurious quoted null string as argv[1] from bat file # simply work around this until we can figure out a better way to handle things if len(argv) == 2: @@ -571,7 +576,7 @@ def main(argv=sys.argv): filenames.append(infile) # start up gui app - app = MainApp(dnd, filenames) + app = MainApp(apphome, dnd, filenames) app.mainloop() return 0 diff --git a/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/flatxml2html.py b/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/flatxml2html.py index 81d93bc..ae2c8dd 100644 --- a/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/flatxml2html.py +++ b/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/flatxml2html.py @@ -68,7 +68,7 @@ class DocParser(object): ys = [] gdefs = [] - # get path defintions, positions, dimensions for ecah glyph + # get path defintions, positions, dimensions for each glyph # that makes up the image, and find min x and min y to reposition origin minx = -1 miny = -1 @@ -305,6 +305,15 @@ class DocParser(object): lastGlyph = firstglyphList[last] else : lastGlyph = len(gidList) + + # handle case of white sapce paragraphs with no actual glyphs in them + # by reverting to text based paragraph + if firstGlyph >= lastGlyph: + # revert to standard text based paragraph + for wordnum in xrange(first, last): + result.append(('ocr', wordnum)) + return pclass, result + for glyphnum in xrange(firstGlyph, lastGlyph): glyphList.append(glyphnum) # include any extratokens if they exist diff --git a/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mobidedrm.py b/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mobidedrm.py index 880690f..776ca6e 100644 --- a/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mobidedrm.py +++ b/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mobidedrm.py @@ -29,7 +29,7 @@ from __future__ import with_statement # and import that ZIP into Calibre using its plugin configuration GUI. -__version__ = '2.1' +__version__ = '2.2' class Unbuffered: def __init__(self, stream): @@ -75,6 +75,7 @@ def zipUpDir(myzip, tempdir,localname): # borrowed from calibre from calibre/src/calibre/__init__.py # added in removal of non-printing chars # and removal of . at start +# convert spaces to underscores def cleanup_name(name): _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') substitute='_' @@ -89,6 +90,7 @@ def cleanup_name(name): # Mac and Unix don't like file names that begin with a full stop if len(one) > 0 and one[0] == '.': one = substitute+one[1:] + one = one.replace(' ','_') return one def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): @@ -248,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, 1) # The version number of this plugin + version = (0, 2, 2) # 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/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mutils.py b/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mutils.py index 1b501ba..5e57701 100644 --- a/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mutils.py +++ b/DeDRM_Windows_Application/DeDRM_WinApp/DeDRM_lib/lib/k4mutils.py @@ -189,6 +189,6 @@ def openKindleInfo(kInfoFile=None): raise DrmException('Error: .kindle-info file can not be found') return open(kinfopath,'r') else: - if not os.path.isfile(kinfoFile): + if not os.path.isfile(kInfoFile): raise DrmException('Error: kindle-info file can not be found') return open(kInfoFile, 'r') diff --git a/DeDRM_Windows_Application/ReadMe_DeDRM_WinApp.txt b/DeDRM_Windows_Application/ReadMe_DeDRM_WinApp.txt index 8e1cfea..73c13b0 100644 --- a/DeDRM_Windows_Application/ReadMe_DeDRM_WinApp.txt +++ b/DeDRM_Windows_Application/ReadMe_DeDRM_WinApp.txt @@ -1,5 +1,5 @@ -ReadMe_DeDRM_WinApp_v1.2 ------------------------ +ReadMe_DeDRM_WinApp_v1.3 +------------------------ 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. diff --git a/KindleBooks_Tools/KindleBooks/KindleBooks.pyw b/KindleBooks_Tools/KindleBooks/KindleBooks.pyw index d4f37fb..63ef77d 100644 --- a/KindleBooks_Tools/KindleBooks/KindleBooks.pyw +++ b/KindleBooks_Tools/KindleBooks/KindleBooks.pyw @@ -207,11 +207,11 @@ class MainDialog(Tkinter.Frame): tpz = False # Identify any Topaz Files - with open(mobipath, 'rb') as f: - raw = f.read(3) - if raw.startswith('TPZ'): - tpz = True - f.close() + f = file(mobipath, 'rb') + raw = f.read(3) + if raw.startswith('TPZ'): + tpz = True + f.close() if not outpath: self.status['text'] = 'No output directory specified' self.sbotton.configure(state='normal') diff --git a/KindleBooks_Tools/KindleBooks/lib/flatxml2html.py b/KindleBooks_Tools/KindleBooks/lib/flatxml2html.py index 81d93bc..ae2c8dd 100644 --- a/KindleBooks_Tools/KindleBooks/lib/flatxml2html.py +++ b/KindleBooks_Tools/KindleBooks/lib/flatxml2html.py @@ -68,7 +68,7 @@ class DocParser(object): ys = [] gdefs = [] - # get path defintions, positions, dimensions for ecah glyph + # get path defintions, positions, dimensions for each glyph # that makes up the image, and find min x and min y to reposition origin minx = -1 miny = -1 @@ -305,6 +305,15 @@ class DocParser(object): lastGlyph = firstglyphList[last] else : lastGlyph = len(gidList) + + # handle case of white sapce paragraphs with no actual glyphs in them + # by reverting to text based paragraph + if firstGlyph >= lastGlyph: + # revert to standard text based paragraph + for wordnum in xrange(first, last): + result.append(('ocr', wordnum)) + return pclass, result + for glyphnum in xrange(firstGlyph, lastGlyph): glyphList.append(glyphnum) # include any extratokens if they exist diff --git a/KindleBooks_Tools/KindleBooks/lib/k4mobidedrm.py b/KindleBooks_Tools/KindleBooks/lib/k4mobidedrm.py index 880690f..776ca6e 100644 --- a/KindleBooks_Tools/KindleBooks/lib/k4mobidedrm.py +++ b/KindleBooks_Tools/KindleBooks/lib/k4mobidedrm.py @@ -29,7 +29,7 @@ from __future__ import with_statement # and import that ZIP into Calibre using its plugin configuration GUI. -__version__ = '2.1' +__version__ = '2.2' class Unbuffered: def __init__(self, stream): @@ -75,6 +75,7 @@ def zipUpDir(myzip, tempdir,localname): # borrowed from calibre from calibre/src/calibre/__init__.py # added in removal of non-printing chars # and removal of . at start +# convert spaces to underscores def cleanup_name(name): _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]') substitute='_' @@ -89,6 +90,7 @@ def cleanup_name(name): # Mac and Unix don't like file names that begin with a full stop if len(one) > 0 and one[0] == '.': one = substitute+one[1:] + one = one.replace(' ','_') return one def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids): @@ -248,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, 1) # The version number of this plugin + version = (0, 2, 2) # 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/KindleBooks_Tools/KindleBooks/lib/k4mutils.py b/KindleBooks_Tools/KindleBooks/lib/k4mutils.py index 1b501ba..5e57701 100644 --- a/KindleBooks_Tools/KindleBooks/lib/k4mutils.py +++ b/KindleBooks_Tools/KindleBooks/lib/k4mutils.py @@ -189,6 +189,6 @@ def openKindleInfo(kInfoFile=None): raise DrmException('Error: .kindle-info file can not be found') return open(kinfopath,'r') else: - if not os.path.isfile(kinfoFile): + if not os.path.isfile(kInfoFile): raise DrmException('Error: kindle-info file can not be found') return open(kInfoFile, 'r') diff --git a/ePub_Fixer/README_ePub_Fixer.txt b/ePub_Fixer/README_ePub_Fixer.txt index b864d07..fb71e9d 100644 --- a/ePub_Fixer/README_ePub_Fixer.txt +++ b/ePub_Fixer/README_ePub_Fixer.txt @@ -1,8 +1,8 @@ ePub_Fixer -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. +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. -ePub_Fixer was designed to fix improperly created zip archives of this type. +ePub_Fixer was designed to fix improperly created zip archives of these types. 1. Simply double-click to launch ePub_Fixer.pyw. diff --git a/eReader_PDB_Tools/lib/eReaderPDB2PML_plugin.py b/eReader_PDB_Tools/lib/eReaderPDB2PML_plugin.py index ad172a3..5585cf5 100644 --- a/eReader_PDB_Tools/lib/eReaderPDB2PML_plugin.py +++ b/eReader_PDB_Tools/lib/eReaderPDB2PML_plugin.py @@ -42,7 +42,7 @@ class eRdrDeDRM(FileTypePlugin): Credit given to The Dark Reverser for the original standalone script.' supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on author = 'DiapDealer' # The author of this plugin - version = (0, 0, 3) # The version number of this plugin + version = (0, 0, 4) # The version number of this plugin file_types = set(['pdb']) # The file types that this plugin will be applied to on_import = True # Run this plugin during the import