tools v3.4

This commit is contained in:
Apprentice Alf 2011-02-08 17:21:51 +00:00
parent 8b632e309f
commit 2bedd75005
29 changed files with 234 additions and 650 deletions

View File

@ -192,6 +192,8 @@ class GParser(object):
argres[j] = int(argres[j])
return result
def getGlyphDim(self, gly):
if self.gdpi[gly] == 0:
return 0, 0
maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly]
maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly]
return maxh, maxw
@ -320,6 +322,18 @@ def generateBook(bookDir, raw, fixedimage):
print 'Processing Meta Data and creating OPF'
meta_array = getMetaArray(metaFile)
# replace special chars in title and authors like & < >
title = meta_array['Title']
title = title.replace('&','&amp;')
title = title.replace('<','&lt;')
title = title.replace('>','&gt;')
meta_array['Title'] = title
authors = meta_array['Authors']
authors = authors.replace('&','&amp;')
authors = authors.replace('<','&lt;')
authors = authors.replace('>','&gt;')
meta_array['Authors'] = authors
xname = os.path.join(xmlDir, 'metadata.xml')
metastr = ''
for key in meta_array:

View File

@ -1,26 +0,0 @@
Installing openssl on Windows 64-bit (Windows 2000 and higher)
Win64 OpenSSL v0.9.8o (8Mb)
http://www.slproweb.com/download/Win64OpenSSL-0_9_8o.exe
(if you get an error message about missing Visual C++ redistributables... cancel the install and install the below support program from Microsoft, THEN install OpenSSL)
Visual C++ 2008 Redistributables (x64) (1.7Mb)
http://www.microsoft.com/downloads/details.aspx?familyid=bd2a6171-e2d6-4230-b809-9a8d7548c1b6
Installing openssl on Windows 32-bit (Windows 2000 and higher)
Win32 OpenSSL v0.9.8o (8Mb)
http://www.slproweb.com/download/Win32OpenSSL-0_9_8o.exe
(if you get an error message about missing Visual C++ redistributables... cancel the install and install the below support program from Microsoft, THEN install OpenSSL)
Visual C++ 2008 Redistributables (1.7Mb)
http://www.microsoft.com/downloads/details.aspx?familyid=9B2DA534-3E03-4391-8A4D-074B9F2BC1BF
Other versions of OpenSSL (and versions for Windows older than Windows 2000) can be found on the following website.
Shining Light Productions
http://www.slproweb.com/products/Win32OpenSSL.html

View File

@ -46,6 +46,8 @@
# - Incorporated SomeUpdates zipfix routine.
# 0.1.2 - bug fix for non-ascii file names in encryption.xml
# 0.1.3 - Try PyCrypto on Windows first
# 0.1.4 - update zipfix to deal with mimetype not in correct place
# 0.1.5 - update zipfix to deal with completely missing mimetype files
"""
Decrypt Barnes & Noble ADEPT encrypted EPUB books.
@ -271,7 +273,7 @@ class IgnobleDeDRM(FileTypePlugin):
Credit given to I <3 Cabbages for the original stand-alone scripts.'
supported_platforms = ['linux', 'osx', 'windows']
author = 'DiapDealer'
version = (0, 1, 4)
version = (0, 1, 5)
minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions.
file_types = set(['epub'])
on_import = True

View File

@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
_EXTRA_LEN_OFFSET = 28
_FILENAME_OFFSET = 30
_MAX_SIZE = 64 * 1024
_MIMETYPE = 'application/epub+zip'
class ZipInfo(zipfile.ZipInfo):
def __init__(self, *args, **kwargs):
if 'compress_type' in kwargs:
compress_type = kwargs.pop('compress_type')
super(ZipInfo, self).__init__(*args, **kwargs)
self.compress_type = compress_type
class fixZip:
def __init__(self, zinput, zoutput):
self.ztype = 'zip'
if zinput.lower().find('.epub') >= 0 :
self.ztype = 'epub'
self.inzip = zipfile.ZipFile(zinput,'r')
self.outzip = zipfile.ZipFile(zoutput,'w')
# open the input zip for reading only as a raw file
@ -81,30 +92,15 @@ class fixZip:
# get the zipinfo for each member of the input archive
# and copy member over to output archive
# if problems exist with local vs central filename, fix them
# also fix bad epub compression
# write mimetype file first, if present, and with no compression
for zinfo in self.inzip.infolist():
if zinfo.filename == "mimetype":
nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
nzinfo.date_time = zinfo.date_time
nzinfo.compress_type = zipfile.ZIP_STORED
nzinfo.flag_bits = 0
nzinfo.internal_attr = 0
nzinfo.extra = ""
self.outzip.writestr(nzinfo,data)
break
# if epub write mimetype file first, with no compression
if self.ztype == 'epub':
nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
self.outzip.writestr(nzinfo, _MIMETYPE)
# write the rest of the files
for zinfo in self.inzip.infolist():
if zinfo.filename != "mimetype":
if zinfo.filename != "mimetype" or self.ztype == '.zip':
data = None
nzinfo = zinfo
try:

Binary file not shown.

View File

@ -47,7 +47,8 @@
# result of Calibre changing to python 2.7.
# 0.1.3 - bug fix for epubs with non-ascii chars in file names
# 0.1.4 - default to try PyCrypto first on Windows
# 0.1.5 - update zipfix to handle out of position mimetypes
# 0.1.6 - update zipfix to handle completely missing mimetype files
"""
Decrypt Adobe ADEPT-encrypted EPUB books.
@ -371,7 +372,7 @@ class IneptDeDRM(FileTypePlugin):
Credit given to I <3 Cabbages for the original stand-alone scripts.'
supported_platforms = ['linux', 'osx', 'windows']
author = 'DiapDealer'
version = (0, 1, 5)
version = (0, 1, 6)
minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions.
file_types = set(['epub'])
on_import = True

View File

@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
_EXTRA_LEN_OFFSET = 28
_FILENAME_OFFSET = 30
_MAX_SIZE = 64 * 1024
_MIMETYPE = 'application/epub+zip'
class ZipInfo(zipfile.ZipInfo):
def __init__(self, *args, **kwargs):
if 'compress_type' in kwargs:
compress_type = kwargs.pop('compress_type')
super(ZipInfo, self).__init__(*args, **kwargs)
self.compress_type = compress_type
class fixZip:
def __init__(self, zinput, zoutput):
self.ztype = 'zip'
if zinput.lower().find('.epub') >= 0 :
self.ztype = 'epub'
self.inzip = zipfile.ZipFile(zinput,'r')
self.outzip = zipfile.ZipFile(zoutput,'w')
# open the input zip for reading only as a raw file
@ -81,30 +92,15 @@ class fixZip:
# get the zipinfo for each member of the input archive
# and copy member over to output archive
# if problems exist with local vs central filename, fix them
# also fix bad epub compression
# write mimetype file first, if present, and with no compression
for zinfo in self.inzip.infolist():
if zinfo.filename == "mimetype":
nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
nzinfo.date_time = zinfo.date_time
nzinfo.compress_type = zipfile.ZIP_STORED
nzinfo.flag_bits = 0
nzinfo.internal_attr = 0
nzinfo.extra = ""
self.outzip.writestr(nzinfo,data)
break
# if epub write mimetype file first, with no compression
if self.ztype == 'epub':
nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
self.outzip.writestr(nzinfo, _MIMETYPE)
# write the rest of the files
for zinfo in self.inzip.infolist():
if zinfo.filename != "mimetype":
if zinfo.filename != "mimetype" or self.ztype == '.zip':
data = None
nzinfo = zinfo
try:

Binary file not shown.

View File

@ -47,7 +47,10 @@
# ** NOTE ** There is no plugin customization data for the Inept PDF DeDRM plugin.
#
# Revision history:
# 0.1 - Initial release
# 0.1 - Initial release
# 0.1.1 - back port ineptpdf 8.4.X support for increased number of encryption methods
# 0.1.2 - back port ineptpdf 8.4.X bug fixes
# 0.1.3 - add in fix for improper rejection of session bookkeys with len(bookkey) = length + 1
"""
Decrypts Adobe ADEPT-encrypted PDF files.
@ -1544,16 +1547,30 @@ class PDFDocument(object):
bookkey = bookkey[index:]
ebx_V = int_value(param.get('V', 4))
ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
# added because of the booktype / decryption book session key error
if ebx_V == 3:
V = 3
elif ebx_V < 4 or ebx_type < 6:
V = ord(bookkey[0])
bookkey = bookkey[1:]
# added because of improper booktype / decryption book session key errors
if length > 0:
if len(bookkey) == length:
if ebx_V == 3:
V = 3
else:
V = 2
elif len(bookkey) == length + 1:
V = ord(bookkey[0])
bookkey = bookkey[1:]
else:
print "ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type)
print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
print "bookkey[0] is %d" % ord(bookkey[0])
raise ADEPTError('error decrypting book session key - mismatched length')
else:
V = 2
if length and len(bookkey) != length:
raise ADEPTError('error decrypting book session key')
# proper length unknown try with whatever you have
print "ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type)
print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
print "bookkey[0] is %d" % ord(bookkey[0])
if ebx_V == 3:
V = 3
else:
V = 2
self.decrypt_key = bookkey
self.genkey = self.genkey_v3 if V == 3 else self.genkey_v2
self.decipher = self.decrypt_rc4
@ -2116,7 +2133,7 @@ class IneptPDFDeDRM(FileTypePlugin):
Credit given to I <3 Cabbages for the original stand-alone scripts.'
supported_platforms = ['linux', 'osx', 'windows']
author = 'DiapDealer'
version = (0, 1, 2)
version = (0, 1, 3)
minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions.
file_types = set(['pdf'])
on_import = True

View File

@ -29,7 +29,7 @@ from __future__ import with_statement
# and import that ZIP into Calibre using its plugin configuration GUI.
__version__ = '2.2'
__version__ = '2.3'
class Unbuffered:
def __init__(self, stream):
@ -250,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
author = 'DiapDealer, SomeUpdates' # The author of this plugin
version = (0, 2, 2) # The version number of this plugin
version = (0, 2, 3) # The version number of this plugin
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm

View File

@ -24,7 +24,7 @@
<key>CFBundleExecutable</key>
<string>droplet</string>
<key>CFBundleGetInfoString</key>
<string>DeDRM 2.1, Copyright © 20102011 by Apprentice Alf and others.</string>
<string>DeDRM 2.2, Copyright © 20102011 by Apprentice Alf and others.</string>
<key>CFBundleIconFile</key>
<string>droplet</string>
<key>CFBundleInfoDictionaryVersion</key>
@ -34,7 +34,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>2.1</string>
<string>2.2</string>
<key>CFBundleSignature</key>
<string>dplt</string>
<key>LSMinimumSystemVersion</key>

View File

@ -192,6 +192,8 @@ class GParser(object):
argres[j] = int(argres[j])
return result
def getGlyphDim(self, gly):
if self.gdpi[gly] == 0:
return 0, 0
maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly]
maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly]
return maxh, maxw
@ -320,6 +322,18 @@ def generateBook(bookDir, raw, fixedimage):
print 'Processing Meta Data and creating OPF'
meta_array = getMetaArray(metaFile)
# replace special chars in title and authors like & < >
title = meta_array['Title']
title = title.replace('&','&amp;')
title = title.replace('<','&lt;')
title = title.replace('>','&gt;')
meta_array['Title'] = title
authors = meta_array['Authors']
authors = authors.replace('&','&amp;')
authors = authors.replace('<','&lt;')
authors = authors.replace('>','&gt;')
meta_array['Authors'] = authors
xname = os.path.join(xmlDir, 'metadata.xml')
metastr = ''
for key in meta_array:

View File

@ -1,5 +1,5 @@
#! /usr/bin/env python
# ineptpdf.pyw, version 7.7
# ineptpdf.pyw, version 7.9
from __future__ import with_statement
@ -33,6 +33,7 @@ from __future__ import with_statement
# 7.6 - backported AES and other fixes from version 8.4.48
# 7.7 - On Windows try PyCrypto first and OpenSSL next
# 7.8 - Modify interface to allow use of import
# 7.9 - Bug fix for some session key errors when len(bookkey) > length required
"""
Decrypts Adobe ADEPT-encrypted PDF files.
@ -1531,16 +1532,30 @@ class PDFDocument(object):
bookkey = bookkey[index:]
ebx_V = int_value(param.get('V', 4))
ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
# added because of the booktype / decryption book session key error
if ebx_V == 3:
V = 3
elif ebx_V < 4 or ebx_type < 6:
V = ord(bookkey[0])
bookkey = bookkey[1:]
# added because of improper booktype / decryption book session key errors
if length > 0:
if len(bookkey) == length:
if ebx_V == 3:
V = 3
else:
V = 2
elif len(bookkey) == length + 1:
V = ord(bookkey[0])
bookkey = bookkey[1:]
else:
print "ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type)
print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
print "bookkey[0] is %d" % ord(bookkey[0])
raise ADEPTError('error decrypting book session key - mismatched length')
else:
V = 2
if length and len(bookkey) != length:
raise ADEPTError('error decrypting book session key')
# proper length unknown try with whatever you have
print "ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type)
print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
print "bookkey[0] is %d" % ord(bookkey[0])
if ebx_V == 3:
V = 3
else:
V = 2
self.decrypt_key = bookkey
self.genkey = self.genkey_v3 if V == 3 else self.genkey_v2
self.decipher = self.decrypt_rc4

View File

@ -29,7 +29,7 @@ from __future__ import with_statement
# and import that ZIP into Calibre using its plugin configuration GUI.
__version__ = '2.2'
__version__ = '2.3'
class Unbuffered:
def __init__(self, stream):
@ -250,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
author = 'DiapDealer, SomeUpdates' # The author of this plugin
version = (0, 2, 2) # The version number of this plugin
version = (0, 2, 3) # The version number of this plugin
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm

View File

@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
_EXTRA_LEN_OFFSET = 28
_FILENAME_OFFSET = 30
_MAX_SIZE = 64 * 1024
_MIMETYPE = 'application/epub+zip'
class ZipInfo(zipfile.ZipInfo):
def __init__(self, *args, **kwargs):
if 'compress_type' in kwargs:
compress_type = kwargs.pop('compress_type')
super(ZipInfo, self).__init__(*args, **kwargs)
self.compress_type = compress_type
class fixZip:
def __init__(self, zinput, zoutput):
self.ztype = 'zip'
if zinput.lower().find('.epub') >= 0 :
self.ztype = 'epub'
self.inzip = zipfile.ZipFile(zinput,'r')
self.outzip = zipfile.ZipFile(zoutput,'w')
# open the input zip for reading only as a raw file
@ -81,30 +92,15 @@ class fixZip:
# get the zipinfo for each member of the input archive
# and copy member over to output archive
# if problems exist with local vs central filename, fix them
# also fix bad epub compression
# write mimetype file first, if present, and with no compression
for zinfo in self.inzip.infolist():
if zinfo.filename == "mimetype":
nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
nzinfo.date_time = zinfo.date_time
nzinfo.compress_type = zipfile.ZIP_STORED
nzinfo.flag_bits = 0
nzinfo.internal_attr = 0
nzinfo.extra = ""
self.outzip.writestr(nzinfo,data)
break
# if epub write mimetype file first, with no compression
if self.ztype == 'epub':
nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
self.outzip.writestr(nzinfo, _MIMETYPE)
# write the rest of the files
for zinfo in self.inzip.infolist():
if zinfo.filename != "mimetype":
if zinfo.filename != "mimetype" or self.ztype == '.zip':
data = None
nzinfo = zinfo
try:

View File

@ -192,6 +192,8 @@ class GParser(object):
argres[j] = int(argres[j])
return result
def getGlyphDim(self, gly):
if self.gdpi[gly] == 0:
return 0, 0
maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly]
maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly]
return maxh, maxw
@ -320,6 +322,18 @@ def generateBook(bookDir, raw, fixedimage):
print 'Processing Meta Data and creating OPF'
meta_array = getMetaArray(metaFile)
# replace special chars in title and authors like & < >
title = meta_array['Title']
title = title.replace('&','&amp;')
title = title.replace('<','&lt;')
title = title.replace('>','&gt;')
meta_array['Title'] = title
authors = meta_array['Authors']
authors = authors.replace('&','&amp;')
authors = authors.replace('<','&lt;')
authors = authors.replace('>','&gt;')
meta_array['Authors'] = authors
xname = os.path.join(xmlDir, 'metadata.xml')
metastr = ''
for key in meta_array:

View File

@ -1,5 +1,5 @@
#! /usr/bin/env python
# ineptpdf.pyw, version 7.7
# ineptpdf.pyw, version 7.9
from __future__ import with_statement
@ -33,6 +33,7 @@ from __future__ import with_statement
# 7.6 - backported AES and other fixes from version 8.4.48
# 7.7 - On Windows try PyCrypto first and OpenSSL next
# 7.8 - Modify interface to allow use of import
# 7.9 - Bug fix for some session key errors when len(bookkey) > length required
"""
Decrypts Adobe ADEPT-encrypted PDF files.
@ -1531,16 +1532,30 @@ class PDFDocument(object):
bookkey = bookkey[index:]
ebx_V = int_value(param.get('V', 4))
ebx_type = int_value(param.get('EBX_ENCRYPTIONTYPE', 6))
# added because of the booktype / decryption book session key error
if ebx_V == 3:
V = 3
elif ebx_V < 4 or ebx_type < 6:
V = ord(bookkey[0])
bookkey = bookkey[1:]
# added because of improper booktype / decryption book session key errors
if length > 0:
if len(bookkey) == length:
if ebx_V == 3:
V = 3
else:
V = 2
elif len(bookkey) == length + 1:
V = ord(bookkey[0])
bookkey = bookkey[1:]
else:
print "ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type)
print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
print "bookkey[0] is %d" % ord(bookkey[0])
raise ADEPTError('error decrypting book session key - mismatched length')
else:
V = 2
if length and len(bookkey) != length:
raise ADEPTError('error decrypting book session key')
# proper length unknown try with whatever you have
print "ebx_V is %d and ebx_type is %d" % (ebx_V, ebx_type)
print "length is %d and len(bookkey) is %d" % (length, len(bookkey))
print "bookkey[0] is %d" % ord(bookkey[0])
if ebx_V == 3:
V = 3
else:
V = 2
self.decrypt_key = bookkey
self.genkey = self.genkey_v3 if V == 3 else self.genkey_v2
self.decipher = self.decrypt_rc4

View File

@ -29,7 +29,7 @@ from __future__ import with_statement
# and import that ZIP into Calibre using its plugin configuration GUI.
__version__ = '2.2'
__version__ = '2.3'
class Unbuffered:
def __init__(self, stream):
@ -250,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
author = 'DiapDealer, SomeUpdates' # The author of this plugin
version = (0, 2, 2) # The version number of this plugin
version = (0, 2, 3) # The version number of this plugin
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm

View File

@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
_EXTRA_LEN_OFFSET = 28
_FILENAME_OFFSET = 30
_MAX_SIZE = 64 * 1024
_MIMETYPE = 'application/epub+zip'
class ZipInfo(zipfile.ZipInfo):
def __init__(self, *args, **kwargs):
if 'compress_type' in kwargs:
compress_type = kwargs.pop('compress_type')
super(ZipInfo, self).__init__(*args, **kwargs)
self.compress_type = compress_type
class fixZip:
def __init__(self, zinput, zoutput):
self.ztype = 'zip'
if zinput.lower().find('.epub') >= 0 :
self.ztype = 'epub'
self.inzip = zipfile.ZipFile(zinput,'r')
self.outzip = zipfile.ZipFile(zoutput,'w')
# open the input zip for reading only as a raw file
@ -81,30 +92,15 @@ class fixZip:
# get the zipinfo for each member of the input archive
# and copy member over to output archive
# if problems exist with local vs central filename, fix them
# also fix bad epub compression
# write mimetype file first, if present, and with no compression
for zinfo in self.inzip.infolist():
if zinfo.filename == "mimetype":
nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
nzinfo.date_time = zinfo.date_time
nzinfo.compress_type = zipfile.ZIP_STORED
nzinfo.flag_bits = 0
nzinfo.internal_attr = 0
nzinfo.extra = ""
self.outzip.writestr(nzinfo,data)
break
# if epub write mimetype file first, with no compression
if self.ztype == 'epub':
nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
self.outzip.writestr(nzinfo, _MIMETYPE)
# write the rest of the files
for zinfo in self.inzip.infolist():
if zinfo.filename != "mimetype":
if zinfo.filename != "mimetype" or self.ztype == '.zip':
data = None
nzinfo = zinfo
try:

View File

@ -1,5 +1,5 @@
ReadMe_DeDRM_WinApp_v1.3
------------------------
ReadMe_DeDRM_WinApp_v1.2
-----------------------
DeDRM_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto theDeDRM_Drop_Target to have the DRM removed. It repackages the"tools" python software in one easy to use program.

View File

@ -192,6 +192,8 @@ class GParser(object):
argres[j] = int(argres[j])
return result
def getGlyphDim(self, gly):
if self.gdpi[gly] == 0:
return 0, 0
maxh = (self.gh[gly] * self.dpi) / self.gdpi[gly]
maxw = (self.gw[gly] * self.dpi) / self.gdpi[gly]
return maxh, maxw
@ -320,6 +322,18 @@ def generateBook(bookDir, raw, fixedimage):
print 'Processing Meta Data and creating OPF'
meta_array = getMetaArray(metaFile)
# replace special chars in title and authors like & < >
title = meta_array['Title']
title = title.replace('&','&amp;')
title = title.replace('<','&lt;')
title = title.replace('>','&gt;')
meta_array['Title'] = title
authors = meta_array['Authors']
authors = authors.replace('&','&amp;')
authors = authors.replace('<','&lt;')
authors = authors.replace('>','&gt;')
meta_array['Authors'] = authors
xname = os.path.join(xmlDir, 'metadata.xml')
metastr = ''
for key in meta_array:

View File

@ -29,7 +29,7 @@ from __future__ import with_statement
# and import that ZIP into Calibre using its plugin configuration GUI.
__version__ = '2.2'
__version__ = '2.3'
class Unbuffered:
def __init__(self, stream):
@ -250,7 +250,7 @@ if not __name__ == "__main__" and inCalibre:
Provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc.'
supported_platforms = ['osx', 'windows', 'linux'] # Platforms this plugin will run on
author = 'DiapDealer, SomeUpdates' # The author of this plugin
version = (0, 2, 2) # The version number of this plugin
version = (0, 2, 3) # The version number of this plugin
file_types = set(['prc','mobi','azw','azw1','tpz']) # The file types that this plugin will be applied to
on_import = True # Run this plugin during the import
priority = 210 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm

View File

@ -1,476 +0,0 @@
# engine to remove drm from Kindle for Mac books
# for personal use for archiving and converting your ebooks
# PLEASE DO NOT PIRATE!
# We want all authors and Publishers, and eBook stores to live long and prosperous lives
#
# it borrows heavily from works by CMBDTC, IHeartCabbages, skindle,
# unswindle, DiapDealer, some_updates and many many others
from __future__ import with_statement
class Unbuffered:
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
import sys
sys.stdout=Unbuffered(sys.stdout)
import os, csv, getopt
from struct import pack
from struct import unpack
import zlib
# for handling sub processes
import subprocess
from subprocess import Popen, PIPE, STDOUT
#Exception Handling
class K4MDEDRMError(Exception):
pass
class K4MDEDRMFatal(Exception):
pass
#
# crypto routines
#
import hashlib
def MD5(message):
ctx = hashlib.md5()
ctx.update(message)
return ctx.digest()
def SHA1(message):
ctx = hashlib.sha1()
ctx.update(message)
return ctx.digest()
def SHA256(message):
ctx = hashlib.sha256()
ctx.update(message)
return ctx.digest()
# interface to needed routines in openssl's libcrypto
def _load_crypto_libcrypto():
from ctypes import CDLL, byref, POINTER, c_void_p, c_char_p, c_int, c_long, \
Structure, c_ulong, create_string_buffer, addressof, string_at, cast
from ctypes.util import find_library
libcrypto = find_library('crypto')
if libcrypto is None:
raise K4MDEDRMError('libcrypto not found')
libcrypto = CDLL(libcrypto)
AES_MAXNR = 14
c_char_pp = POINTER(c_char_p)
c_int_p = POINTER(c_int)
class AES_KEY(Structure):
_fields_ = [('rd_key', c_long * (4 * (AES_MAXNR + 1))), ('rounds', c_int)]
AES_KEY_p = POINTER(AES_KEY)
def F(restype, name, argtypes):
func = getattr(libcrypto, name)
func.restype = restype
func.argtypes = argtypes
return func
AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,c_int])
AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',[c_char_p, c_int, AES_KEY_p])
PKCS5_PBKDF2_HMAC_SHA1 = F(c_int, 'PKCS5_PBKDF2_HMAC_SHA1',
[c_char_p, c_ulong, c_char_p, c_ulong, c_ulong, c_ulong, c_char_p])
class LibCrypto(object):
def __init__(self):
self._blocksize = 0
self._keyctx = None
self.iv = 0
def set_decrypt_key(self, userkey, iv):
self._blocksize = len(userkey)
if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) :
raise K4MDEDRMError('AES improper key used')
return
keyctx = self._keyctx = AES_KEY()
self.iv = iv
rv = AES_set_decrypt_key(userkey, len(userkey) * 8, keyctx)
if rv < 0:
raise K4MDEDRMError('Failed to initialize AES key')
def decrypt(self, data):
out = create_string_buffer(len(data))
rv = AES_cbc_encrypt(data, out, len(data), self._keyctx, self.iv, 0)
if rv == 0:
raise K4MDEDRMError('AES decryption failed')
return out.raw
def keyivgen(self, passwd):
salt = '16743'
saltlen = 5
passlen = len(passwd)
iter = 0x3e8
keylen = 80
out = create_string_buffer(keylen)
rv = PKCS5_PBKDF2_HMAC_SHA1(passwd, passlen, salt, saltlen, iter, keylen, out)
return out.raw
return LibCrypto
def _load_crypto():
LibCrypto = None
try:
LibCrypto = _load_crypto_libcrypto()
except (ImportError, K4MDEDRMError):
pass
return LibCrypto
LibCrypto = _load_crypto()
#
# Utility Routines
#
# uses a sub process to get the Hard Drive Serial Number using ioreg
# returns with the first found serial number in that class
def GetVolumeSerialNumber():
sernum = os.getenv('MYSERIALNUMBER')
if sernum != None:
return sernum
cmdline = '/usr/sbin/ioreg -l -S -w 0 -r -c AppleAHCIDiskDriver'
cmdline = cmdline.encode(sys.getfilesystemencoding())
p = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
poll = p.wait('wait')
results = p.read()
reslst = results.split('\n')
cnt = len(reslst)
bsdname = None
sernum = None
foundIt = False
for j in xrange(cnt):
resline = reslst[j]
pp = resline.find('"Serial Number" = "')
if pp >= 0:
sernum = resline[pp+19:-1]
sernum = sernum.strip()
bb = resline.find('"BSD Name" = "')
if bb >= 0:
bsdname = resline[bb+14:-1]
bsdname = bsdname.strip()
if (bsdname == 'disk0') and (sernum != None):
foundIt = True
break
if not foundIt:
sernum = '9999999999'
return sernum
# uses unix env to get username instead of using sysctlbyname
def GetUserName():
username = os.getenv('USER')
return username
MAX_PATH = 255
#
# start of Kindle specific routines
#
global kindleDatabase
# Various character maps used to decrypt books. Probably supposed to act as obfuscation
charMap1 = "n5Pr6St7Uv8Wx9YzAb0Cd1Ef2Gh3Jk4M"
charMap2 = "ZB0bYyc1xDdW2wEV3Ff7KkPpL8UuGA4gz-Tme9Nn_tHh5SvXCsIiR6rJjQaqlOoM"
charMap3 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
charMap4 = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789"
# Encode the bytes in data with the characters in map
def encode(data, map):
result = ""
for char in data:
value = ord(char)
Q = (value ^ 0x80) // len(map)
R = value % len(map)
result += map[Q]
result += map[R]
return result
# Hash the bytes in data and then encode the digest with the characters in map
def encodeHash(data,map):
return encode(MD5(data),map)
# Decode the string in data with the characters in map. Returns the decoded bytes
def decode(data,map):
result = ""
for i in range (0,len(data)-1,2):
high = map.find(data[i])
low = map.find(data[i+1])
if (high == -1) or (low == -1) :
break
value = (((high * len(map)) ^ 0x80) & 0xFF) + low
result += pack("B",value)
return result
# implements an Pseudo Mac Version of Windows built-in Crypto routine
def CryptUnprotectData(encryptedData):
sp = GetVolumeSerialNumber() + '!@#' + GetUserName()
passwdData = encode(SHA256(sp),charMap1)
crp = LibCrypto()
key_iv = crp.keyivgen(passwdData)
key = key_iv[0:32]
iv = key_iv[32:48]
crp.set_decrypt_key(key,iv)
cleartext = crp.decrypt(encryptedData)
return cleartext
# Locate and open the .kindle-info file
def openKindleInfo():
home = os.getenv('HOME')
kinfopath = home + '/Library/Application Support/Amazon/Kindle/storage/.kindle-info'
if not os.path.exists(kinfopath):
kinfopath = home + '/Library/Application Support/Amazon/Kindle for Mac/storage/.kindle-info'
if not os.path.exists(kinfopath):
raise K4MDEDRMError('Error: .kindle-info file can not be found')
return open(kinfopath,'r')
# Parse the Kindle.info file and return the records as a list of key-values
def parseKindleInfo():
DB = {}
infoReader = openKindleInfo()
infoReader.read(1)
data = infoReader.read()
items = data.split('[')
for item in items:
splito = item.split(':')
DB[splito[0]] =splito[1]
return DB
# Get a record from the Kindle.info file for the key "hashedKey" (already hashed and encoded). Return the decoded and decrypted record
def getKindleInfoValueForHash(hashedKey):
global kindleDatabase
encryptedValue = decode(kindleDatabase[hashedKey],charMap2)
cleartext = CryptUnprotectData(encryptedValue)
return decode(cleartext, charMap1)
# Get a record from the Kindle.info file for the string in "key" (plaintext). Return the decoded and decrypted record
def getKindleInfoValueForKey(key):
return getKindleInfoValueForHash(encodeHash(key,charMap2))
# Find if the original string for a hashed/encoded string is known. If so return the original string othwise return an empty string.
def findNameForHash(hash):
names = ["kindle.account.tokens","kindle.cookie.item","eulaVersionAccepted","login_date","kindle.token.item","login","kindle.key.item","kindle.name.info","kindle.device.info", "MazamaRandomNumber"]
result = ""
for name in names:
if hash == encodeHash(name, charMap2):
result = name
break
return result
# Print all the records from the kindle.info file (option -i)
def printKindleInfo():
for record in kindleDatabase:
name = findNameForHash(record)
if name != "" :
print (name)
print ("--------------------------")
else :
print ("Unknown Record")
print getKindleInfoValueForHash(record)
print "\n"
#
# PID generation routines
#
# Returns two bit at offset from a bit field
def getTwoBitsFromBitField(bitField,offset):
byteNumber = offset // 4
bitPosition = 6 - 2*(offset % 4)
return ord(bitField[byteNumber]) >> bitPosition & 3
# Returns the six bits at offset from a bit field
def getSixBitsFromBitField(bitField,offset):
offset *= 3
value = (getTwoBitsFromBitField(bitField,offset) <<4) + (getTwoBitsFromBitField(bitField,offset+1) << 2) +getTwoBitsFromBitField(bitField,offset+2)
return value
# 8 bits to six bits encoding from hash to generate PID string
def encodePID(hash):
global charMap3
PID = ""
for position in range (0,8):
PID += charMap3[getSixBitsFromBitField(hash,position)]
return PID
#
# Main
#
def main(argv=sys.argv):
global kindleDatabase
kindleDatabase = None
#
# Read the encrypted database
#
try:
kindleDatabase = parseKindleInfo()
except Exception, message:
print(message)
if kindleDatabase != None :
printKindleInfo()
return 0
import signal
import threading
import subprocess
from subprocess import Popen, PIPE, STDOUT
# **heavily** chopped up and modfied version of asyncproc.py
# to make it actually work on Windows as well as Mac/Linux
# For the original see:
# "http://www.lysator.liu.se/~bellman/download/"
# author is "Thomas Bellman <bellman@lysator.liu.se>"
# available under GPL version 3 or Later
# create an asynchronous subprocess whose output can be collected in
# a non-blocking manner
# What a mess! Have to use threads just to get non-blocking io
# in a cross-platform manner
# luckily all thread use is hidden within this class
class Process(object):
def __init__(self, *params, **kwparams):
if len(params) <= 3:
kwparams.setdefault('stdin', subprocess.PIPE)
if len(params) <= 4:
kwparams.setdefault('stdout', subprocess.PIPE)
if len(params) <= 5:
kwparams.setdefault('stderr', subprocess.PIPE)
self.__pending_input = []
self.__collected_outdata = []
self.__collected_errdata = []
self.__exitstatus = None
self.__lock = threading.Lock()
self.__inputsem = threading.Semaphore(0)
self.__quit = False
self.__process = subprocess.Popen(*params, **kwparams)
if self.__process.stdin:
self.__stdin_thread = threading.Thread(
name="stdin-thread",
target=self.__feeder, args=(self.__pending_input,
self.__process.stdin))
self.__stdin_thread.setDaemon(True)
self.__stdin_thread.start()
if self.__process.stdout:
self.__stdout_thread = threading.Thread(
name="stdout-thread",
target=self.__reader, args=(self.__collected_outdata,
self.__process.stdout))
self.__stdout_thread.setDaemon(True)
self.__stdout_thread.start()
if self.__process.stderr:
self.__stderr_thread = threading.Thread(
name="stderr-thread",
target=self.__reader, args=(self.__collected_errdata,
self.__process.stderr))
self.__stderr_thread.setDaemon(True)
self.__stderr_thread.start()
def pid(self):
return self.__process.pid
def kill(self, signal):
self.__process.send_signal(signal)
# check on subprocess (pass in 'nowait') to act like poll
def wait(self, flag):
if flag.lower() == 'nowait':
rc = self.__process.poll()
else:
rc = self.__process.wait()
if rc != None:
if self.__process.stdin:
self.closeinput()
if self.__process.stdout:
self.__stdout_thread.join()
if self.__process.stderr:
self.__stderr_thread.join()
return self.__process.returncode
def terminate(self):
if self.__process.stdin:
self.closeinput()
self.__process.terminate()
# thread gets data from subprocess stdout
def __reader(self, collector, source):
while True:
data = os.read(source.fileno(), 65536)
self.__lock.acquire()
collector.append(data)
self.__lock.release()
if data == "":
source.close()
break
return
# thread feeds data to subprocess stdin
def __feeder(self, pending, drain):
while True:
self.__inputsem.acquire()
self.__lock.acquire()
if not pending and self.__quit:
drain.close()
self.__lock.release()
break
data = pending.pop(0)
self.__lock.release()
drain.write(data)
# non-blocking read of data from subprocess stdout
def read(self):
self.__lock.acquire()
outdata = "".join(self.__collected_outdata)
del self.__collected_outdata[:]
self.__lock.release()
return outdata
# non-blocking read of data from subprocess stderr
def readerr(self):
self.__lock.acquire()
errdata = "".join(self.__collected_errdata)
del self.__collected_errdata[:]
self.__lock.release()
return errdata
# non-blocking write to stdin of subprocess
def write(self, data):
if self.__process.stdin is None:
raise ValueError("Writing to process with stdin not a pipe")
self.__lock.acquire()
self.__pending_input.append(data)
self.__inputsem.release()
self.__lock.release()
# close stdinput of subprocess
def closeinput(self):
self.__lock.acquire()
self.__quit = True
self.__inputsem.release()
self.__lock.release()
if __name__ == '__main__':
sys.exit(main())

View File

@ -1,8 +1,8 @@
ePub_Fixer
ePubs are specially crafted zip archives whose first file is an uncompresssed "mimetype" file. Unfortunately, many of the DRM encoded Adobe Adept and Barnes & Noble ePubs are not "proper" zip archives in that the names of some files in the zip central directory do NOT match the local name given in archive itself, or they do not have an uncompressed mimetype file as the first file in the archive. These types of epubs are technically incorrect/corrupted and can not be read by many other programs.
ePubs are specially crafted zip archives. Unfortunately, many of the DRM encoded Adobe Adept and Barnes & Noble ePubs are not "proper" zip archives in that the names of some files in the zip central directory do NOT match the local name given in archive itself. This type of zip archive is technically incorrect/corrupted and can not be read by many other programs.
ePub_Fixer was designed to fix improperly created zip archives of these types.
ePub_Fixer was designed to fix improperly created zip archives of this type.
1. Simply double-click to launch ePub_Fixer.pyw.

View File

@ -13,9 +13,20 @@ _FILENAME_LEN_OFFSET = 26
_EXTRA_LEN_OFFSET = 28
_FILENAME_OFFSET = 30
_MAX_SIZE = 64 * 1024
_MIMETYPE = 'application/epub+zip'
class ZipInfo(zipfile.ZipInfo):
def __init__(self, *args, **kwargs):
if 'compress_type' in kwargs:
compress_type = kwargs.pop('compress_type')
super(ZipInfo, self).__init__(*args, **kwargs)
self.compress_type = compress_type
class fixZip:
def __init__(self, zinput, zoutput):
self.ztype = 'zip'
if zinput.lower().find('.epub') >= 0 :
self.ztype = 'epub'
self.inzip = zipfile.ZipFile(zinput,'r')
self.outzip = zipfile.ZipFile(zoutput,'w')
# open the input zip for reading only as a raw file
@ -81,30 +92,15 @@ class fixZip:
# get the zipinfo for each member of the input archive
# and copy member over to output archive
# if problems exist with local vs central filename, fix them
# also fix bad epub compression
# write mimetype file first, if present, and with no compression
for zinfo in self.inzip.infolist():
if zinfo.filename == "mimetype":
nzinfo = zinfo
try:
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
nzinfo.filename = local_name
nzinfo.date_time = zinfo.date_time
nzinfo.compress_type = zipfile.ZIP_STORED
nzinfo.flag_bits = 0
nzinfo.internal_attr = 0
nzinfo.extra = ""
self.outzip.writestr(nzinfo,data)
break
# if epub write mimetype file first, with no compression
if self.ztype == 'epub':
nzinfo = ZipInfo('mimetype', compress_type=zipfile.ZIP_STORED)
self.outzip.writestr(nzinfo, _MIMETYPE)
# write the rest of the files
for zinfo in self.inzip.infolist():
if zinfo.filename != "mimetype":
if zinfo.filename != "mimetype" or self.ztype == '.zip':
data = None
nzinfo = zinfo
try: