tools v3.3

This commit is contained in:
Apprentice Alf 2011-02-02 14:41:15 +00:00
parent bc968f8eca
commit 8b632e309f
38 changed files with 454 additions and 1366 deletions

View file

@ -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

View file

@ -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,62 +393,14 @@ def convertEreaderToPml(infile, name, cc, outdir):
# file(os.path.join(outdir, 'bookinfo.txt'),'wb').write(bkinfo)
def usage():
print "Converts DRMed eReader books to PML Source"
print "Usage:"
print " erdr2pml [options] infile.pdb [outdir] \"your name\" credit_card_number "
print " "
print "Options: "
print " -h prints this message"
print " --make-pmlz create PMLZ instead of using output directory"
print " "
print "Note:"
print " if ommitted, outdir defaults based on 'infile.pdb'"
print " It's enough to enter the last 8 digits of the credit card number"
return
def main(argv=None):
global bookname
try:
opts, args = getopt.getopt(sys.argv[1:], "h", ["make-pmlz"])
except getopt.GetoptError, err:
print str(err)
usage()
return 1
make_pmlz = False
zipname = None
for o, a in opts:
if o == "-h":
usage()
return 0
elif o == "--make-pmlz":
make_pmlz = True
zipname = ''
print "eRdr2Pml v%s. Copyright (c) 2009 The Dark Reverser" % __version__
if len(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]
def decryptBook(infile, outdir, name, cc, make_pmlz):
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
@ -469,11 +424,6 @@ def main(argv=None):
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
@ -483,6 +433,52 @@ def main(argv=None):
return 1
return 0
def usage():
print "Converts DRMed eReader books to PML Source"
print "Usage:"
print " erdr2pml [options] infile.pdb [outdir] \"your name\" credit_card_number "
print " "
print "Options: "
print " -h prints this message"
print " --make-pmlz create PMLZ instead of using output directory"
print " "
print "Note:"
print " if ommitted, outdir defaults based on 'infile.pdb'"
print " It's enough to enter the last 8 digits of the credit card number"
return
def main(argv=None):
try:
opts, args = getopt.getopt(sys.argv[1:], "h", ["make-pmlz"])
except getopt.GetoptError, err:
print str(err)
usage()
return 1
make_pmlz = False
for o, a in opts:
if o == "-h":
usage()
return 0
elif o == "--make-pmlz":
make_pmlz = True
print "eRdr2Pml v%s. Copyright (c) 2009 The Dark Reverser" % __version__
if len(args)!=3 and len(args)!=4:
usage()
return 1
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())

View file

@ -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

View file

@ -81,13 +81,34 @@ 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
for i, zinfo in enumerate(self.inzip.infolist()):
# 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)
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
@ -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())

Binary file not shown.

View file

@ -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

View file

@ -81,13 +81,34 @@ 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
for i, zinfo in enumerate(self.inzip.infolist()):
# 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)
data = self.inzip.read(zinfo.filename)
except zipfile.BadZipfile or zipfile.error:
local_name = self.getlocalname(zinfo)
data = self.getfiledata(zinfo)
@ -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())

Binary file not shown.

View file

@ -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

View file

@ -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')

View file

@ -24,7 +24,7 @@
<key>CFBundleExecutable</key>
<string>droplet</string>
<key>CFBundleGetInfoString</key>
<string>DeDRM 2.0, Copyright © 20102011 by Apprentice Alf.</string>
<string>DeDRM 2.1, 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.0</string>
<string>2.1</string>
<key>CFBundleSignature</key>
<string>dplt</string>
<key>LSMinimumSystemVersion</key>
@ -43,14 +43,18 @@
<true/>
<key>WindowState</key>
<dict>
<key>dividerCollapsed</key>
<true/>
<key>eventLogLevel</key>
<integer>-1</integer>
<key>name</key>
<string>ScriptWindowState</string>
<key>positionOfDivider</key>
<real>709</real>
<real>0.0</real>
<key>savedFrame</key>
<string>1617 62 862 788 1440 -150 1680 1050 </string>
<string>1578 27 862 788 1440 -150 1680 1050 </string>
<key>selectedTabView</key>
<string>result</string>
<string>event log</string>
</dict>
</dict>
</plist>

View file

@ -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())

View file

@ -1,4 +1,4 @@
{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf540
{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350
{\fonttbl}
{\colortbl;\red255\green255\blue255;}
}

View file

@ -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

View file

@ -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(''))

View file

@ -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 <http://www.python.org/download/>
# 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())

View file

@ -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 <http://www.python.org/download/>
# 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:

View file

@ -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:

View file

@ -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()

View file

@ -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:

View file

@ -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):
@ -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,8 +136,9 @@ 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)
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)
@ -143,6 +146,7 @@ def decryptBook(infile, outdir, k4, kInfoFiles, serials, pids):
myzip.close()
shutil.rmtree(tempdir, True)
return 1
pass
if mobi:
outfile = os.path.join(outdir,outfilename + '_nodrm' + '.mobi')
@ -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

View file

@ -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')

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -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.

View file

@ -207,7 +207,7 @@ class MainDialog(Tkinter.Frame):
tpz = False
# Identify any Topaz Files
with open(mobipath, 'rb') as f:
f = file(mobipath, 'rb')
raw = f.read(3)
if raw.startswith('TPZ'):
tpz = True

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -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.

View file

@ -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