# 0.4.10 - Another Topaz Fix (class added to page and group and region)
# 0.4.11 - Fixed Linux support of K4PC
# 0.4.12 - More Linux Wine fixes
+# 0.4.13 - Ancient Mobipocket files fix
"""
Decrypt Amazon Kindle and Mobipocket encrypted ebooks.
"""
PLUGIN_NAME = u"Kindle and Mobipocket DeDRM"
-PLUGIN_VERSION_TUPLE = (0, 4, 12)
+PLUGIN_VERSION_TUPLE = (0, 4, 13)
PLUGIN_VERSION = '.'.join([str(x) for x in PLUGIN_VERSION_TUPLE])
import sys, os, re
'word_semantic' : (1, 'snippets', 1, 1),
'word_semantic.type' : (1, 'scalar_text', 0, 0),
+ 'word_semantic.class' : (1, 'scalar_text', 0, 0),
'word_semantic.firstWord' : (1, 'scalar_number', 0, 0),
'word_semantic.lastWord' : (1, 'scalar_number', 0, 0),
'word.lastGlyph' : (1, 'scalar_number', 0, 0),
'_span' : (1, 'snippets', 1, 0),
+ '_span.class' : (1, 'scalar_text', 0, 0),
'_span.firstWord' : (1, 'scalar_number', 0, 0),
'_span.lastWord' : (1, 'scalar_number', 0, 0),
'_span.gridSize' : (1, 'scalar_number', 0, 0),
'version.paragraph_continuation' : (1, 'scalar_text', 0, 0),
'version.toc' : (1, 'scalar_text', 0, 0),
- 'stylesheet' : (1, 'snippets', 1, 0),
- 'style' : (1, 'snippets', 1, 0),
- 'style._tag' : (1, 'scalar_text', 0, 0),
- 'style.type' : (1, 'scalar_text', 0, 0),
- 'style._parent_type' : (1, 'scalar_text', 0, 0),
- 'style.class' : (1, 'scalar_text', 0, 0),
- 'style._after_class' : (1, 'scalar_text', 0, 0),
- 'rule' : (1, 'snippets', 1, 0),
- 'rule.attr' : (1, 'scalar_text', 0, 0),
- 'rule.value' : (1, 'scalar_text', 0, 0),
+ 'stylesheet' : (1, 'snippets', 1, 0),
+ 'style' : (1, 'snippets', 1, 0),
+ 'style._tag' : (1, 'scalar_text', 0, 0),
+ 'style.type' : (1, 'scalar_text', 0, 0),
+ 'style._after_type' : (1, 'scalar_text', 0, 0),
+ 'style._parent_type' : (1, 'scalar_text', 0, 0),
+ 'style._after_parent_type' : (1, 'scalar_text', 0, 0),
+ 'style.class' : (1, 'scalar_text', 0, 0),
+ 'style._after_class' : (1, 'scalar_text', 0, 0),
+ 'rule' : (1, 'snippets', 1, 0),
+ 'rule.attr' : (1, 'scalar_text', 0, 0),
+ 'rule.value' : (1, 'scalar_text', 0, 0),
'original' : (0, 'number', 1, 1),
'original.pnum' : (1, 'number', 0, 0),
from struct import pack
from struct import unpack
+debug = False
class DocParser(object):
def __init__(self, flatxml, fontsize, ph, pw):
# process each style converting what you can
+ if debug: print ' ', 'Processing styles.'
for j in xrange(stylecnt):
+ if debug: print ' ', 'Processing style %d' %(j)
start = styleList[j]
end = styleList[j+1]
else :
sclass = ''
+ if debug: print 'sclass', sclass
+
# check for any "after class" specifiers
(pos, aftclass) = self.findinDoc('style._after_class',start,end)
if aftclass != None:
else :
aftclass = ''
+ if debug: print 'aftclass', aftclass
+
cssargs = {}
while True :
(pos1, attr) = self.findinDoc('style.rule.attr', start, end)
(pos2, val) = self.findinDoc('style.rule.value', start, end)
+ if debug: print 'attr', attr
+ if debug: print 'val', val
+
if attr == None : break
if (attr == 'display') or (attr == 'pos') or (attr == 'align'):
scale = self.pw
elif attr == 'line-space':
scale = self.fontsize * 2.0
-
+
if val == "":
val = 0
if aftclass != "" : keep = False
if keep :
+ if debug: print 'keeping style'
# make sure line-space does not go below 100% or above 300% since
# it can be wacky in some styles
if 'line-space' in cssargs:
# create a document parser
dp = DocParser(flatxml, fontsize, ph, pw)
+ if debug: print ' ', 'Created DocParser.'
csspage = dp.process()
+ if debug: print ' ', 'Processed DocParser.'
return csspage
argvencoding = 'utf-8'
return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv]
+#global switch
+debug = False
+
if 'calibre' in sys.modules:
inCalibre = True
from calibre_plugins.k4mobidedrm import kgenpids
# Read and return the data of one header record at the current book file position
# [[offset,decompressedLength,compressedLength],...]
nbValues = bookReadEncodedNumber(self.fo)
+ if debug: print "%d records in header " % nbValues,
values = []
for i in range (0,nbValues):
values.append([bookReadEncodedNumber(self.fo),bookReadEncodedNumber(self.fo),bookReadEncodedNumber(self.fo)])
record = bookReadHeaderRecordData()
return [tag,record]
nbRecords = bookReadEncodedNumber(self.fo)
+ if debug: print "Headers: %d" % nbRecords
for i in range (0,nbRecords):
result = parseTopazHeaderRecord()
- # print result[0], result[1]
+ if debug: print result[0], ": ", result[1]
self.bookHeaderRecords[result[0]] = result[1]
if ord(self.fo.read(1)) != 0x64 :
raise DrmException(u"Parse Error : Invalid Header")
raise DrmException(u"Parse Error : Record Names Don't Match")
flags = ord(self.fo.read(1))
nbRecords = ord(self.fo.read(1))
- # print nbRecords
+ if debug: print "Metadata Records: %d" % nbRecords
for i in range (0,nbRecords) :
keyval = bookReadString(self.fo)
content = bookReadString(self.fo)
- # print keyval
- # print content
+ if debug: print keyval
+ if debug: print content
self.bookMetadata[keyval] = content
return self.bookMetadata
\i not
\i0 need to install Python.\
\
-Drag the DeDRM application from from tools_v5.5\\DeDRM_Applications\\Macintosh (the location of this ReadMe) to your Applications folder, or anywhere else you find convenient.\
+Drag the DeDRM application from from tools_v5.5.3\\DeDRM_Applications\\Macintosh (the location of this ReadMe) to your Applications folder, or anywhere else you find convenient.\
\
\
<key>CFBundleExecutable</key>
<string>droplet</string>
<key>CFBundleGetInfoString</key>
- <string>DeDRM 5.5. AppleScript written 2010–2012 by Apprentice Alf and others.</string>
+ <string>DeDRM 5.5.3. AppleScript written 2010–2012 by Apprentice Alf and others.</string>
<key>CFBundleIconFile</key>
<string>DeDRM</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
- <string>DeDRM 5.5</string>
+ <string>DeDRM 5.5.3</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>5.5</string>
+ <string>5.5.3</string>
<key>CFBundleSignature</key>
<string>dplt</string>
<key>LSRequiresCarbon</key>
'word_semantic' : (1, 'snippets', 1, 1),
'word_semantic.type' : (1, 'scalar_text', 0, 0),
+ 'word_semantic.class' : (1, 'scalar_text', 0, 0),
'word_semantic.firstWord' : (1, 'scalar_number', 0, 0),
'word_semantic.lastWord' : (1, 'scalar_number', 0, 0),
'word.lastGlyph' : (1, 'scalar_number', 0, 0),
'_span' : (1, 'snippets', 1, 0),
+ '_span.class' : (1, 'scalar_text', 0, 0),
'_span.firstWord' : (1, 'scalar_number', 0, 0),
'_span.lastWord' : (1, 'scalar_number', 0, 0),
'_span.gridSize' : (1, 'scalar_number', 0, 0),
'version.paragraph_continuation' : (1, 'scalar_text', 0, 0),
'version.toc' : (1, 'scalar_text', 0, 0),
- 'stylesheet' : (1, 'snippets', 1, 0),
- 'style' : (1, 'snippets', 1, 0),
- 'style._tag' : (1, 'scalar_text', 0, 0),
- 'style.type' : (1, 'scalar_text', 0, 0),
- 'style._parent_type' : (1, 'scalar_text', 0, 0),
- 'style.class' : (1, 'scalar_text', 0, 0),
- 'style._after_class' : (1, 'scalar_text', 0, 0),
- 'rule' : (1, 'snippets', 1, 0),
- 'rule.attr' : (1, 'scalar_text', 0, 0),
- 'rule.value' : (1, 'scalar_text', 0, 0),
+ 'stylesheet' : (1, 'snippets', 1, 0),
+ 'style' : (1, 'snippets', 1, 0),
+ 'style._tag' : (1, 'scalar_text', 0, 0),
+ 'style.type' : (1, 'scalar_text', 0, 0),
+ 'style._after_type' : (1, 'scalar_text', 0, 0),
+ 'style._parent_type' : (1, 'scalar_text', 0, 0),
+ 'style._after_parent_type' : (1, 'scalar_text', 0, 0),
+ 'style.class' : (1, 'scalar_text', 0, 0),
+ 'style._after_class' : (1, 'scalar_text', 0, 0),
+ 'rule' : (1, 'snippets', 1, 0),
+ 'rule.attr' : (1, 'scalar_text', 0, 0),
+ 'rule.value' : (1, 'scalar_text', 0, 0),
'original' : (0, 'number', 1, 1),
'original.pnum' : (1, 'number', 0, 0),
import sys
-class Unbuffered:
+class SafeUnbuffered:
def __init__(self, stream):
self.stream = stream
+ self.encoding = stream.encoding
+ if self.encoding == None:
+ self.encoding = "utf-8"
def write(self, data):
+ if isinstance(data,unicode):
+ data = data.encode(self.encoding,"replace")
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
-sys.stdout=Unbuffered(sys.stdout)
+sys.stdout=SafeUnbuffered(sys.stdout)
+sys.stderr=SafeUnbuffered(sys.stderr)
import os
import struct
mobi = False
if mobi:
- mb = mobidedrm.MobiBook(path_to_ebook,False)
+ mb = mobidedrm.MobiBook(path_to_ebook)
else:
mb = topazextract.TopazBook(path_to_ebook)
from struct import pack
from struct import unpack
+debug = False
class DocParser(object):
def __init__(self, flatxml, fontsize, ph, pw):
# process each style converting what you can
+ if debug: print ' ', 'Processing styles.'
for j in xrange(stylecnt):
+ if debug: print ' ', 'Processing style %d' %(j)
start = styleList[j]
end = styleList[j+1]
else :
sclass = ''
+ if debug: print 'sclass', sclass
+
# check for any "after class" specifiers
(pos, aftclass) = self.findinDoc('style._after_class',start,end)
if aftclass != None:
else :
aftclass = ''
+ if debug: print 'aftclass', aftclass
+
cssargs = {}
while True :
(pos1, attr) = self.findinDoc('style.rule.attr', start, end)
(pos2, val) = self.findinDoc('style.rule.value', start, end)
+ if debug: print 'attr', attr
+ if debug: print 'val', val
+
if attr == None : break
if (attr == 'display') or (attr == 'pos') or (attr == 'align'):
scale = self.pw
elif attr == 'line-space':
scale = self.fontsize * 2.0
-
+
if val == "":
val = 0
if aftclass != "" : keep = False
if keep :
+ if debug: print 'keeping style'
# make sure line-space does not go below 100% or above 300% since
# it can be wacky in some styles
if 'line-space' in cssargs:
# create a document parser
dp = DocParser(flatxml, fontsize, ph, pw)
+ if debug: print ' ', 'Created DocParser.'
csspage = dp.process()
+ if debug: print ' ', 'Processed DocParser.'
return csspage
argvencoding = 'utf-8'
return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv]
+#global switch
+debug = False
+
if 'calibre' in sys.modules:
inCalibre = True
from calibre_plugins.k4mobidedrm import kgenpids
# Read and return the data of one header record at the current book file position
# [[offset,decompressedLength,compressedLength],...]
nbValues = bookReadEncodedNumber(self.fo)
+ if debug: print "%d records in header " % nbValues,
values = []
for i in range (0,nbValues):
values.append([bookReadEncodedNumber(self.fo),bookReadEncodedNumber(self.fo),bookReadEncodedNumber(self.fo)])
record = bookReadHeaderRecordData()
return [tag,record]
nbRecords = bookReadEncodedNumber(self.fo)
+ if debug: print "Headers: %d" % nbRecords
for i in range (0,nbRecords):
result = parseTopazHeaderRecord()
- # print result[0], result[1]
+ if debug: print result[0], ": ", result[1]
self.bookHeaderRecords[result[0]] = result[1]
if ord(self.fo.read(1)) != 0x64 :
raise DrmException(u"Parse Error : Invalid Header")
raise DrmException(u"Parse Error : Record Names Don't Match")
flags = ord(self.fo.read(1))
nbRecords = ord(self.fo.read(1))
- # print nbRecords
+ if debug: print "Metadata Records: %d" % nbRecords
for i in range (0,nbRecords) :
keyval = bookReadString(self.fo)
content = bookReadString(self.fo)
- # print keyval
- # print content
+ if debug: print keyval
+ if debug: print content
self.bookMetadata[keyval] = content
return self.bookMetadata
#!/usr/bin/env python
# -*- coding: utf-8 -*-
-# DeDRM.pyw, version 5.5
+# DeDRM.pyw, version 5.5.3
# By some_updates and Apprentice Alf
import sys
import simpleprefs
-__version__ = '5.5'
+__version__ = '5.5.3'
class DrmException(Exception):
pass
self.log += text
self.log += msg
else:
+ msg = u"\nFailed\n"
text = self.p2.read().decode('utf8')
text += self.p2.readerr().decode('utf8')
msg += text
- msg += u"\nFailed\n"
self.numbad += 1
self.log += msg
self.showCmdOutput(msg)
'word_semantic' : (1, 'snippets', 1, 1),
'word_semantic.type' : (1, 'scalar_text', 0, 0),
+ 'word_semantic.class' : (1, 'scalar_text', 0, 0),
'word_semantic.firstWord' : (1, 'scalar_number', 0, 0),
'word_semantic.lastWord' : (1, 'scalar_number', 0, 0),
'word.lastGlyph' : (1, 'scalar_number', 0, 0),
'_span' : (1, 'snippets', 1, 0),
+ '_span.class' : (1, 'scalar_text', 0, 0),
'_span.firstWord' : (1, 'scalar_number', 0, 0),
'_span.lastWord' : (1, 'scalar_number', 0, 0),
'_span.gridSize' : (1, 'scalar_number', 0, 0),
'version.paragraph_continuation' : (1, 'scalar_text', 0, 0),
'version.toc' : (1, 'scalar_text', 0, 0),
- 'stylesheet' : (1, 'snippets', 1, 0),
- 'style' : (1, 'snippets', 1, 0),
- 'style._tag' : (1, 'scalar_text', 0, 0),
- 'style.type' : (1, 'scalar_text', 0, 0),
- 'style._parent_type' : (1, 'scalar_text', 0, 0),
- 'style.class' : (1, 'scalar_text', 0, 0),
- 'style._after_class' : (1, 'scalar_text', 0, 0),
- 'rule' : (1, 'snippets', 1, 0),
- 'rule.attr' : (1, 'scalar_text', 0, 0),
- 'rule.value' : (1, 'scalar_text', 0, 0),
+ 'stylesheet' : (1, 'snippets', 1, 0),
+ 'style' : (1, 'snippets', 1, 0),
+ 'style._tag' : (1, 'scalar_text', 0, 0),
+ 'style.type' : (1, 'scalar_text', 0, 0),
+ 'style._after_type' : (1, 'scalar_text', 0, 0),
+ 'style._parent_type' : (1, 'scalar_text', 0, 0),
+ 'style._after_parent_type' : (1, 'scalar_text', 0, 0),
+ 'style.class' : (1, 'scalar_text', 0, 0),
+ 'style._after_class' : (1, 'scalar_text', 0, 0),
+ 'rule' : (1, 'snippets', 1, 0),
+ 'rule.attr' : (1, 'scalar_text', 0, 0),
+ 'rule.value' : (1, 'scalar_text', 0, 0),
'original' : (0, 'number', 1, 1),
'original.pnum' : (1, 'number', 0, 0),
import sys
-class Unbuffered:
+class SafeUnbuffered:
def __init__(self, stream):
self.stream = stream
+ self.encoding = stream.encoding
+ if self.encoding == None:
+ self.encoding = "utf-8"
def write(self, data):
+ if isinstance(data,unicode):
+ data = data.encode(self.encoding,"replace")
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
-sys.stdout=Unbuffered(sys.stdout)
+sys.stdout=SafeUnbuffered(sys.stdout)
+sys.stderr=SafeUnbuffered(sys.stderr)
import os
import struct
mobi = False
if mobi:
- mb = mobidedrm.MobiBook(path_to_ebook,False)
+ mb = mobidedrm.MobiBook(path_to_ebook)
else:
mb = topazextract.TopazBook(path_to_ebook)
from struct import pack
from struct import unpack
+debug = False
class DocParser(object):
def __init__(self, flatxml, fontsize, ph, pw):
# process each style converting what you can
+ if debug: print ' ', 'Processing styles.'
for j in xrange(stylecnt):
+ if debug: print ' ', 'Processing style %d' %(j)
start = styleList[j]
end = styleList[j+1]
else :
sclass = ''
+ if debug: print 'sclass', sclass
+
# check for any "after class" specifiers
(pos, aftclass) = self.findinDoc('style._after_class',start,end)
if aftclass != None:
else :
aftclass = ''
+ if debug: print 'aftclass', aftclass
+
cssargs = {}
while True :
(pos1, attr) = self.findinDoc('style.rule.attr', start, end)
(pos2, val) = self.findinDoc('style.rule.value', start, end)
+ if debug: print 'attr', attr
+ if debug: print 'val', val
+
if attr == None : break
if (attr == 'display') or (attr == 'pos') or (attr == 'align'):
scale = self.pw
elif attr == 'line-space':
scale = self.fontsize * 2.0
-
+
if val == "":
val = 0
if aftclass != "" : keep = False
if keep :
+ if debug: print 'keeping style'
# make sure line-space does not go below 100% or above 300% since
# it can be wacky in some styles
if 'line-space' in cssargs:
# create a document parser
dp = DocParser(flatxml, fontsize, ph, pw)
+ if debug: print ' ', 'Created DocParser.'
csspage = dp.process()
+ if debug: print ' ', 'Processed DocParser.'
return csspage
argvencoding = 'utf-8'
return [arg if (type(arg) == unicode) else unicode(arg,argvencoding) for arg in sys.argv]
+#global switch
+debug = False
+
if 'calibre' in sys.modules:
inCalibre = True
from calibre_plugins.k4mobidedrm import kgenpids
# Read and return the data of one header record at the current book file position
# [[offset,decompressedLength,compressedLength],...]
nbValues = bookReadEncodedNumber(self.fo)
+ if debug: print "%d records in header " % nbValues,
values = []
for i in range (0,nbValues):
values.append([bookReadEncodedNumber(self.fo),bookReadEncodedNumber(self.fo),bookReadEncodedNumber(self.fo)])
record = bookReadHeaderRecordData()
return [tag,record]
nbRecords = bookReadEncodedNumber(self.fo)
+ if debug: print "Headers: %d" % nbRecords
for i in range (0,nbRecords):
result = parseTopazHeaderRecord()
- # print result[0], result[1]
+ if debug: print result[0], ": ", result[1]
self.bookHeaderRecords[result[0]] = result[1]
if ord(self.fo.read(1)) != 0x64 :
raise DrmException(u"Parse Error : Invalid Header")
raise DrmException(u"Parse Error : Record Names Don't Match")
flags = ord(self.fo.read(1))
nbRecords = ord(self.fo.read(1))
- # print nbRecords
+ if debug: print "Metadata Records: %d" % nbRecords
for i in range (0,nbRecords) :
keyval = bookReadString(self.fo)
content = bookReadString(self.fo)
- # print keyval
- # print content
+ if debug: print keyval
+ if debug: print content
self.bookMetadata[keyval] = content
return self.bookMetadata
-ReadMe_DeDRM_v5.5_WinApp
+ReadMe_DeDRM_v5.5.3_WinApp
========================
-DeDRM_v5.5_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages all the "tools" python software in one easy to use program that remembers preferences and settings.
+DeDRM_v5.5.3_WinApp is a pure python drag and drop application that allows users to drag and drop ebooks or folders of ebooks onto the DeDRM_Drop_Target to have the DRM removed. It repackages all the "tools" python software in one easy to use program that remembers preferences and settings.
It will work without manual configuration for Kindle for PC ebooks and Adobe Adept epub and pdf ebooks.
0. If you don't already have a correct version of Python and PyCrypto installed, follow the "Installing Python on Windows" and "Installing PyCrypto on Windows" sections below before continuing.
-1. Drag the DeDRM_5.5 folder from tools_v5.5/DeDRM_Applications/Windows to your "My Documents" folder.
+1. Drag the DeDRM_5.5.3 folder from tools_v5.5.3/DeDRM_Applications/Windows to your "My Documents" folder.
-2. Open the DeDRM_5.5 folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop.
+2. Open the DeDRM_5.5.3 folder you've just dragged, and make a short-cut of the DeDRM_Drop_Target.bat file (right-click/Create Shortcut). Drag the shortcut file onto your Desktop.
3. To set the preferences simply double-click on your just created short-cut.