mirror of
https://github.com/noDRM/DeDRM_tools.git
synced 2026-03-21 05:18:56 +00:00
tools v2.2
This commit is contained in:
26
Calibre_Plugins/Win_OpenSSL_0.9.8o.txt
Normal file
26
Calibre_Plugins/Win_OpenSSL_0.9.8o.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
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
|
||||
Binary file not shown.
@@ -1,21 +0,0 @@
|
||||
eReader PDB2PML - eReaderPDB2PML_vXX_plugin.zip
|
||||
|
||||
All credit given to The Dark Reverser for the original standalone script. I had the much easier job of converting it to a Calibre plugin.
|
||||
|
||||
This plugin is meant to convert secure Ereader files (PDB) to unsecured PMLZ files. Calibre can then convert it to whatever format you desire. It is meant to function without having to install any dependencies... other than having Calibre installed, of course. I've included the psyco libraries (compiled for each platform) for speed. If your system can use them, great! Otherwise, they won't be used and things will just work slower.
|
||||
|
||||
Installation:
|
||||
Go to Calibre's Preferences page... click on the Plugins button. Use the file dialog button to select the plugin's zip file (eReaderPDB2PML_vXX_plugin.zip) and click the 'Add' button. You're done.
|
||||
|
||||
Configuration:
|
||||
Highlight the plugin (eReader PDB 2 PML under the "File type plugins" category) and click the "Customize Plugin" button on Calibre's Preferences->Plugins page. Enter your name and last 8 digits of the credit card number separated by a comma: Your Name,12341234
|
||||
|
||||
If you've purchased books with more than one credit card, separate the info with a colon: Your Name,12341234:Other Name,23452345 (NOTE: Do NOT put quotes around your name like you do with the original script!!)
|
||||
|
||||
Troubleshooting:
|
||||
If you find that it's not working for you (imported pdb's are not converted to pmlz format), you can save a lot of time and trouble by trying to add the pdb to Calibre with the command line tools. This will print out a lot of helpful debugging info that can be copied into any online help requests. I'm going to ask you to do it first, anyway, so you might
|
||||
as well get used to it. ;)
|
||||
|
||||
Open a command prompt (terminal) and change to the directory where the ebook you're trying to import resides. Then type the command "calibredb add your_ebook.pdb". Don't type the quotes and obviously change the 'your_ebook.pdb' to whatever the filename of your book is. Copy the resulting output and paste it into any online help request you make.
|
||||
|
||||
** Note: the Mac version of Calibre doesn't install the command line tools by default. If you go to the 'Preferences' page and click on the miscellaneous button, you'll see the option to install the command line tools.
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# eReaderPDB2PML_v01_plugin.py
|
||||
# eReaderPDB2PML_plugin.py
|
||||
# Released under the terms of the GNU General Public Licence, version 3 or
|
||||
# later. <http://www.gnu.org/licenses/>
|
||||
#
|
||||
@@ -30,7 +30,8 @@
|
||||
# NOTE: Do NOT put quotes around your name like you do with the original script!!
|
||||
#
|
||||
# Revision history:
|
||||
# 0.1 - Initial release
|
||||
# 0.0.1 - Initial release
|
||||
# 0.0.2 - updated to distinguish it from earlier non-openssl version
|
||||
|
||||
import sys, os
|
||||
|
||||
@@ -42,7 +43,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, 1) # The version number of this plugin
|
||||
version = (0, 0, 2) # 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
|
||||
|
||||
@@ -52,7 +53,6 @@ class eRdrDeDRM(FileTypePlugin):
|
||||
pdir = 'windows' if iswindows else 'osx' if isosx else 'linux'
|
||||
ppath = os.path.join(self.sys_insertion_path, pdir)
|
||||
sys.path.insert(0, ppath)
|
||||
#sys.path.append(ppath)
|
||||
|
||||
global bookname, erdr2pml
|
||||
import erdr2pml
|
||||
|
||||
@@ -54,26 +54,30 @@
|
||||
# 0.13 - change to unbuffered stdout for use with gui front ends
|
||||
# 0.14 - contributed enhancement to support --make-pmlz switch
|
||||
# 0.15 - enabled high-ascii to pml character encoding. DropBook now works on Mac.
|
||||
# 0.16 - convert to use openssl DES (very very fast) or pure python DES if openssl's libcrypto is not available
|
||||
|
||||
__version__='0.15'
|
||||
Des = None
|
||||
|
||||
# Import Psyco if available
|
||||
try:
|
||||
# Dumb speed hack 1
|
||||
# http://psyco.sourceforge.net
|
||||
import psyco
|
||||
psyco.full()
|
||||
pass
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
# Dumb speed hack 2
|
||||
# All map() calls converted to list comprehension (some use zip)
|
||||
# override zip with izip - saves memory and in rough testing
|
||||
# appears to be faster zip() is only used in the converted map() calls
|
||||
from itertools import izip as zip
|
||||
except ImportError:
|
||||
pass
|
||||
import openssl_des
|
||||
Des = openssl_des.load_libcrypto()
|
||||
|
||||
# if that did not work then use pure python implementation
|
||||
# of DES and try to speed it up with Psycho
|
||||
if Des == None:
|
||||
import python_des
|
||||
Des = python_des.Des
|
||||
# Import Psyco if available
|
||||
try:
|
||||
# Dumb speed hack 1
|
||||
# http://psyco.sourceforge.net
|
||||
import psyco
|
||||
psyco.full()
|
||||
pass
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
__version__='0.16'
|
||||
|
||||
class Unbuffered:
|
||||
def __init__(self, stream):
|
||||
@@ -101,223 +105,6 @@ import logging
|
||||
logging.basicConfig()
|
||||
#logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
ECB = 0
|
||||
CBC = 1
|
||||
class Des(object):
|
||||
__pc1 = [56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
|
||||
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
|
||||
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
|
||||
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3]
|
||||
__left_rotations = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
|
||||
__pc2 = [13, 16, 10, 23, 0, 4,2, 27, 14, 5, 20, 9,
|
||||
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
|
||||
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
|
||||
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31]
|
||||
__ip = [57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
|
||||
61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7,
|
||||
56, 48, 40, 32, 24, 16, 8, 0, 58, 50, 42, 34, 26, 18, 10, 2,
|
||||
60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6]
|
||||
__expansion_table = [31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8,
|
||||
7, 8, 9, 10, 11, 12,11, 12, 13, 14, 15, 16,
|
||||
15, 16, 17, 18, 19, 20,19, 20, 21, 22, 23, 24,
|
||||
23, 24, 25, 26, 27, 28,27, 28, 29, 30, 31, 0]
|
||||
__sbox = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
|
||||
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
|
||||
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
|
||||
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],
|
||||
[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
|
||||
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
|
||||
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
|
||||
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],
|
||||
[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
|
||||
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
|
||||
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
|
||||
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],
|
||||
[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
|
||||
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
|
||||
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
|
||||
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],
|
||||
[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
|
||||
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
|
||||
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
|
||||
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],
|
||||
[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
|
||||
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
|
||||
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
|
||||
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],
|
||||
[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
|
||||
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
|
||||
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
|
||||
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],
|
||||
[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
|
||||
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
|
||||
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
|
||||
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],]
|
||||
__p = [15, 6, 19, 20, 28, 11,27, 16, 0, 14, 22, 25,
|
||||
4, 17, 30, 9, 1, 7,23,13, 31, 26, 2, 8,18, 12, 29, 5, 21, 10,3, 24]
|
||||
__fp = [39, 7, 47, 15, 55, 23, 63, 31,38, 6, 46, 14, 54, 22, 62, 30,
|
||||
37, 5, 45, 13, 53, 21, 61, 29,36, 4, 44, 12, 52, 20, 60, 28,
|
||||
35, 3, 43, 11, 51, 19, 59, 27,34, 2, 42, 10, 50, 18, 58, 26,
|
||||
33, 1, 41, 9, 49, 17, 57, 25,32, 0, 40, 8, 48, 16, 56, 24]
|
||||
# Type of crypting being done
|
||||
ENCRYPT = 0x00
|
||||
DECRYPT = 0x01
|
||||
def __init__(self, key, mode=ECB, IV=None):
|
||||
if len(key) != 8:
|
||||
raise ValueError("Invalid DES key size. Key must be exactly 8 bytes long.")
|
||||
self.block_size = 8
|
||||
self.key_size = 8
|
||||
self.__padding = ''
|
||||
self.setMode(mode)
|
||||
if IV:
|
||||
self.setIV(IV)
|
||||
self.L = []
|
||||
self.R = []
|
||||
self.Kn = [ [0] * 48 ] * 16 # 16 48-bit keys (K1 - K16)
|
||||
self.final = []
|
||||
self.setKey(key)
|
||||
def getKey(self):
|
||||
return self.__key
|
||||
def setKey(self, key):
|
||||
self.__key = key
|
||||
self.__create_sub_keys()
|
||||
def getMode(self):
|
||||
return self.__mode
|
||||
def setMode(self, mode):
|
||||
self.__mode = mode
|
||||
def getIV(self):
|
||||
return self.__iv
|
||||
def setIV(self, IV):
|
||||
if not IV or len(IV) != self.block_size:
|
||||
raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes")
|
||||
self.__iv = IV
|
||||
def getPadding(self):
|
||||
return self.__padding
|
||||
def __String_to_BitList(self, data):
|
||||
l = len(data) * 8
|
||||
result = [0] * l
|
||||
pos = 0
|
||||
for c in data:
|
||||
i = 7
|
||||
ch = ord(c)
|
||||
while i >= 0:
|
||||
if ch & (1 << i) != 0:
|
||||
result[pos] = 1
|
||||
else:
|
||||
result[pos] = 0
|
||||
pos += 1
|
||||
i -= 1
|
||||
return result
|
||||
def __BitList_to_String(self, data):
|
||||
result = ''
|
||||
pos = 0
|
||||
c = 0
|
||||
while pos < len(data):
|
||||
c += data[pos] << (7 - (pos % 8))
|
||||
if (pos % 8) == 7:
|
||||
result += chr(c)
|
||||
c = 0
|
||||
pos += 1
|
||||
return result
|
||||
def __permutate(self, table, block):
|
||||
return [block[x] for x in table]
|
||||
def __create_sub_keys(self):
|
||||
key = self.__permutate(Des.__pc1, self.__String_to_BitList(self.getKey()))
|
||||
i = 0
|
||||
self.L = key[:28]
|
||||
self.R = key[28:]
|
||||
while i < 16:
|
||||
j = 0
|
||||
while j < Des.__left_rotations[i]:
|
||||
self.L.append(self.L[0])
|
||||
del self.L[0]
|
||||
self.R.append(self.R[0])
|
||||
del self.R[0]
|
||||
j += 1
|
||||
self.Kn[i] = self.__permutate(Des.__pc2, self.L + self.R)
|
||||
i += 1
|
||||
def __des_crypt(self, block, crypt_type):
|
||||
block = self.__permutate(Des.__ip, block)
|
||||
self.L = block[:32]
|
||||
self.R = block[32:]
|
||||
if crypt_type == Des.ENCRYPT:
|
||||
iteration = 0
|
||||
iteration_adjustment = 1
|
||||
else:
|
||||
iteration = 15
|
||||
iteration_adjustment = -1
|
||||
i = 0
|
||||
while i < 16:
|
||||
tempR = self.R[:]
|
||||
self.R = self.__permutate(Des.__expansion_table, self.R)
|
||||
self.R = [x ^ y for x,y in zip(self.R, self.Kn[iteration])]
|
||||
B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]]
|
||||
j = 0
|
||||
Bn = [0] * 32
|
||||
pos = 0
|
||||
while j < 8:
|
||||
m = (B[j][0] << 1) + B[j][5]
|
||||
n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]
|
||||
v = Des.__sbox[j][(m << 4) + n]
|
||||
Bn[pos] = (v & 8) >> 3
|
||||
Bn[pos + 1] = (v & 4) >> 2
|
||||
Bn[pos + 2] = (v & 2) >> 1
|
||||
Bn[pos + 3] = v & 1
|
||||
pos += 4
|
||||
j += 1
|
||||
self.R = self.__permutate(Des.__p, Bn)
|
||||
self.R = [x ^ y for x, y in zip(self.R, self.L)]
|
||||
self.L = tempR
|
||||
i += 1
|
||||
iteration += iteration_adjustment
|
||||
self.final = self.__permutate(Des.__fp, self.R + self.L)
|
||||
return self.final
|
||||
def crypt(self, data, crypt_type):
|
||||
if not data:
|
||||
return ''
|
||||
if len(data) % self.block_size != 0:
|
||||
if crypt_type == Des.DECRYPT: # Decryption must work on 8 byte blocks
|
||||
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n.")
|
||||
if not self.getPadding():
|
||||
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character")
|
||||
else:
|
||||
data += (self.block_size - (len(data) % self.block_size)) * self.getPadding()
|
||||
if self.getMode() == CBC:
|
||||
if self.getIV():
|
||||
iv = self.__String_to_BitList(self.getIV())
|
||||
else:
|
||||
raise ValueError("For CBC mode, you must supply the Initial Value (IV) for ciphering")
|
||||
i = 0
|
||||
dict = {}
|
||||
result = []
|
||||
while i < len(data):
|
||||
block = self.__String_to_BitList(data[i:i+8])
|
||||
if self.getMode() == CBC:
|
||||
if crypt_type == Des.ENCRYPT:
|
||||
block = [x ^ y for x, y in zip(block, iv)]
|
||||
processed_block = self.__des_crypt(block, crypt_type)
|
||||
if crypt_type == Des.DECRYPT:
|
||||
processed_block = [x ^ y for x, y in zip(processed_block, iv)]
|
||||
iv = block
|
||||
else:
|
||||
iv = processed_block
|
||||
else:
|
||||
processed_block = self.__des_crypt(block, crypt_type)
|
||||
result.append(self.__BitList_to_String(processed_block))
|
||||
i += 8
|
||||
if crypt_type == Des.DECRYPT and self.getPadding():
|
||||
s = result[-1]
|
||||
while s[-1] == self.getPadding():
|
||||
s = s[:-1]
|
||||
result[-1] = s
|
||||
return ''.join(result)
|
||||
def encrypt(self, data, pad=''):
|
||||
self.__padding = pad
|
||||
return self.crypt(data, Des.ENCRYPT)
|
||||
def decrypt(self, data, pad=''):
|
||||
self.__padding = pad
|
||||
return self.crypt(data, Des.DECRYPT)
|
||||
|
||||
class Sectionizer(object):
|
||||
def __init__(self, filename, ident):
|
||||
self.contents = file(filename, 'rb').read()
|
||||
@@ -685,8 +472,5 @@ def main(argv=None):
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
#import cProfile
|
||||
#command = """sys.exit(main())"""
|
||||
#cProfile.runctx( command, globals(), locals(), filename="cprofile.profile" )
|
||||
|
||||
sys.exit(main())
|
||||
|
||||
|
||||
90
Calibre_Plugins/eReaderPDB2PML_plugin/openssl_des.py
Normal file
90
Calibre_Plugins/eReaderPDB2PML_plugin/openssl_des.py
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:ts=4:sw=4:softtabstop=4:smarttab:expandtab
|
||||
|
||||
# implement just enough of des from openssl to make erdr2pml.py happy
|
||||
|
||||
def load_libcrypto():
|
||||
from ctypes import CDLL, POINTER, c_void_p, c_char_p, c_char, c_int, c_long, \
|
||||
Structure, c_ulong, create_string_buffer, cast
|
||||
from ctypes.util import find_library
|
||||
import sys
|
||||
|
||||
if sys.platform.startswith('win'):
|
||||
libcrypto = find_library('libeay32')
|
||||
else:
|
||||
libcrypto = find_library('crypto')
|
||||
|
||||
if libcrypto is None:
|
||||
return None
|
||||
|
||||
libcrypto = CDLL(libcrypto)
|
||||
|
||||
# typedef struct DES_ks
|
||||
# {
|
||||
# union
|
||||
# {
|
||||
# DES_cblock cblock;
|
||||
# /* make sure things are correct size on machines with
|
||||
# * 8 byte longs */
|
||||
# DES_LONG deslong[2];
|
||||
# } ks[16];
|
||||
# } DES_key_schedule;
|
||||
|
||||
# just create a big enough place to hold everything
|
||||
# it will have alignment of structure so we should be okay (16 byte aligned?)
|
||||
class DES_KEY_SCHEDULE(Structure):
|
||||
_fields_ = [('DES_cblock1', c_char * 16),
|
||||
('DES_cblock2', c_char * 16),
|
||||
('DES_cblock3', c_char * 16),
|
||||
('DES_cblock4', c_char * 16),
|
||||
('DES_cblock5', c_char * 16),
|
||||
('DES_cblock6', c_char * 16),
|
||||
('DES_cblock7', c_char * 16),
|
||||
('DES_cblock8', c_char * 16),
|
||||
('DES_cblock9', c_char * 16),
|
||||
('DES_cblock10', c_char * 16),
|
||||
('DES_cblock11', c_char * 16),
|
||||
('DES_cblock12', c_char * 16),
|
||||
('DES_cblock13', c_char * 16),
|
||||
('DES_cblock14', c_char * 16),
|
||||
('DES_cblock15', c_char * 16),
|
||||
('DES_cblock16', c_char * 16)]
|
||||
|
||||
DES_KEY_SCHEDULE_p = POINTER(DES_KEY_SCHEDULE)
|
||||
|
||||
def F(restype, name, argtypes):
|
||||
func = getattr(libcrypto, name)
|
||||
func.restype = restype
|
||||
func.argtypes = argtypes
|
||||
return func
|
||||
|
||||
DES_set_key = F(None, 'DES_set_key',[c_char_p, DES_KEY_SCHEDULE_p])
|
||||
DES_ecb_encrypt = F(None, 'DES_ecb_encrypt',[c_char_p, c_char_p, DES_KEY_SCHEDULE_p, c_int])
|
||||
|
||||
|
||||
class DES(object):
|
||||
def __init__(self, key):
|
||||
if len(key) != 8 :
|
||||
raise Error('DES improper key used')
|
||||
return
|
||||
self.key = key
|
||||
self.keyschedule = DES_KEY_SCHEDULE()
|
||||
DES_set_key(self.key, self.keyschedule)
|
||||
def desdecrypt(self, data):
|
||||
ob = create_string_buffer(len(data))
|
||||
DES_ecb_encrypt(data, ob, self.keyschedule, 0)
|
||||
return ob.raw
|
||||
def decrypt(self, data):
|
||||
if not data:
|
||||
return ''
|
||||
i = 0
|
||||
result = []
|
||||
while i < len(data):
|
||||
block = data[i:i+8]
|
||||
processed_block = self.desdecrypt(block)
|
||||
result.append(processed_block)
|
||||
i += 8
|
||||
return ''.join(result)
|
||||
|
||||
return DES
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 41
|
||||
/svn/!svn/ver/70200/psyco/dist/py-support
|
||||
END
|
||||
core.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 49
|
||||
/svn/!svn/ver/70200/psyco/dist/py-support/core.py
|
||||
END
|
||||
support.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 52
|
||||
/svn/!svn/ver/49315/psyco/dist/py-support/support.py
|
||||
END
|
||||
classes.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 52
|
||||
/svn/!svn/ver/35003/psyco/dist/py-support/classes.py
|
||||
END
|
||||
__init__.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 53
|
||||
/svn/!svn/ver/35003/psyco/dist/py-support/__init__.py
|
||||
END
|
||||
logger.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 51
|
||||
/svn/!svn/ver/23284/psyco/dist/py-support/logger.py
|
||||
END
|
||||
kdictproxy.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 55
|
||||
/svn/!svn/ver/35003/psyco/dist/py-support/kdictproxy.py
|
||||
END
|
||||
profiler.py
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 53
|
||||
/svn/!svn/ver/70200/psyco/dist/py-support/profiler.py
|
||||
END
|
||||
@@ -1,7 +0,0 @@
|
||||
K 10
|
||||
svn:ignore
|
||||
V 14
|
||||
*~
|
||||
*.pyc
|
||||
*.pyo
|
||||
END
|
||||
@@ -1,266 +0,0 @@
|
||||
10
|
||||
|
||||
dir
|
||||
78269
|
||||
http://codespeak.net/svn/psyco/dist/py-support
|
||||
http://codespeak.net/svn
|
||||
|
||||
|
||||
|
||||
2009-12-18T16:35:35.119276Z
|
||||
70200
|
||||
arigo
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
fd0d7bf2-dfb6-0310-8d31-b7ecfe96aada
|
||||
|
||||
core.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-25T15:10:42.000000Z
|
||||
3b362177a839893c9e867880b3a7cef3
|
||||
2009-12-18T16:35:35.119276Z
|
||||
70200
|
||||
arigo
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
8144
|
||||
|
||||
support.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-25T15:10:42.000000Z
|
||||
b0551e975d774f2f7f58a29ed4b6b90e
|
||||
2007-12-03T12:27:25.632574Z
|
||||
49315
|
||||
arigo
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
6043
|
||||
|
||||
classes.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-25T15:10:42.000000Z
|
||||
5932ed955198d16ec17285dfb195d341
|
||||
2006-11-26T13:03:26.949973Z
|
||||
35003
|
||||
arigo
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1440
|
||||
|
||||
__init__.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-25T15:10:42.000000Z
|
||||
219582b5182dfa38a9119d059a71965f
|
||||
2006-11-26T13:03:26.949973Z
|
||||
35003
|
||||
arigo
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1895
|
||||
|
||||
logger.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-25T15:10:42.000000Z
|
||||
aa21f905df036af43082e1ea2a2561ee
|
||||
2006-02-13T15:02:51.744168Z
|
||||
23284
|
||||
arigo
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2678
|
||||
|
||||
kdictproxy.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-25T15:10:42.000000Z
|
||||
1c8611748dcee5b29848bf25be3ec473
|
||||
2006-11-26T13:03:26.949973Z
|
||||
35003
|
||||
arigo
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
4369
|
||||
|
||||
profiler.py
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2010-10-25T15:10:42.000000Z
|
||||
858162366cbc39cd9e249e35e6f510c4
|
||||
2009-12-18T16:35:35.119276Z
|
||||
70200
|
||||
arigo
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
11238
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
K 13
|
||||
svn:eol-style
|
||||
V 6
|
||||
native
|
||||
K 12
|
||||
svn:keywords
|
||||
V 23
|
||||
Author Date Id Revision
|
||||
END
|
||||
@@ -1,9 +0,0 @@
|
||||
K 13
|
||||
svn:eol-style
|
||||
V 6
|
||||
native
|
||||
K 12
|
||||
svn:keywords
|
||||
V 23
|
||||
Author Date Id Revision
|
||||
END
|
||||
@@ -1,9 +0,0 @@
|
||||
K 13
|
||||
svn:eol-style
|
||||
V 6
|
||||
native
|
||||
K 12
|
||||
svn:keywords
|
||||
V 23
|
||||
Author Date Id Revision
|
||||
END
|
||||
@@ -1,9 +0,0 @@
|
||||
K 13
|
||||
svn:eol-style
|
||||
V 6
|
||||
native
|
||||
K 12
|
||||
svn:keywords
|
||||
V 23
|
||||
Author Date Id Revision
|
||||
END
|
||||
@@ -1,9 +0,0 @@
|
||||
K 13
|
||||
svn:eol-style
|
||||
V 6
|
||||
native
|
||||
K 12
|
||||
svn:keywords
|
||||
V 23
|
||||
Author Date Id Revision
|
||||
END
|
||||
@@ -1,9 +0,0 @@
|
||||
K 13
|
||||
svn:eol-style
|
||||
V 6
|
||||
native
|
||||
K 12
|
||||
svn:keywords
|
||||
V 23
|
||||
Author Date Id Revision
|
||||
END
|
||||
@@ -1,9 +0,0 @@
|
||||
K 13
|
||||
svn:eol-style
|
||||
V 6
|
||||
native
|
||||
K 12
|
||||
svn:keywords
|
||||
V 23
|
||||
Author Date Id Revision
|
||||
END
|
||||
@@ -1,54 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco top-level file of the Psyco package.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco -- the Python Specializing Compiler.
|
||||
|
||||
Typical usage: add the following lines to your application's main module,
|
||||
preferably after the other imports:
|
||||
|
||||
try:
|
||||
import psyco
|
||||
psyco.full()
|
||||
except ImportError:
|
||||
print 'Psyco not installed, the program will just run slower'
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
|
||||
#
|
||||
# This module is present to make 'psyco' a package and to
|
||||
# publish the main functions and variables.
|
||||
#
|
||||
# More documentation can be found in core.py.
|
||||
#
|
||||
|
||||
|
||||
# Try to import the dynamic-loading _psyco and report errors
|
||||
try:
|
||||
import _psyco
|
||||
except ImportError, e:
|
||||
extramsg = ''
|
||||
import sys, imp
|
||||
try:
|
||||
file, filename, (suffix, mode, type) = imp.find_module('_psyco', __path__)
|
||||
except ImportError:
|
||||
ext = [suffix for suffix, mode, type in imp.get_suffixes()
|
||||
if type == imp.C_EXTENSION]
|
||||
if ext:
|
||||
extramsg = (" (cannot locate the compiled extension '_psyco%s' "
|
||||
"in the package path '%s')" % (ext[0], '; '.join(__path__)))
|
||||
else:
|
||||
extramsg = (" (check that the compiled extension '%s' is for "
|
||||
"the correct Python version; this is Python %s)" %
|
||||
(filename, sys.version.split()[0]))
|
||||
raise ImportError, str(e) + extramsg
|
||||
|
||||
# Publish important data by importing them in the package
|
||||
from support import __version__, error, warning, _getrealframe, _getemulframe
|
||||
from support import version_info, __version__ as hexversion
|
||||
from core import full, profile, background, runonly, stop, cannotcompile
|
||||
from core import log, bind, unbind, proxy, unproxy, dumpcodebuf
|
||||
from _psyco import setfilter
|
||||
from _psyco import compact, compacttype
|
||||
@@ -1,42 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco class support module.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco class support module.
|
||||
|
||||
'psyco.classes.psyobj' is an alternate Psyco-optimized root for classes.
|
||||
Any class inheriting from it or using the metaclass '__metaclass__' might
|
||||
get optimized specifically for Psyco. It is equivalent to call
|
||||
psyco.bind() on the class object after its creation.
|
||||
|
||||
Importing everything from psyco.classes in a module will import the
|
||||
'__metaclass__' name, so all classes defined after a
|
||||
|
||||
from psyco.classes import *
|
||||
|
||||
will automatically use the Psyco-optimized metaclass.
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
__all__ = ['psyobj', 'psymetaclass', '__metaclass__']
|
||||
|
||||
|
||||
from _psyco import compacttype
|
||||
import core
|
||||
from types import FunctionType
|
||||
|
||||
class psymetaclass(compacttype):
|
||||
"Psyco-optimized meta-class. Turns all methods into Psyco proxies."
|
||||
|
||||
def __new__(cls, name, bases, dict):
|
||||
bindlist = dict.get('__psyco__bind__')
|
||||
if bindlist is None:
|
||||
bindlist = [key for key, value in dict.items()
|
||||
if isinstance(value, FunctionType)]
|
||||
for attr in bindlist:
|
||||
dict[attr] = core.proxy(dict[attr])
|
||||
return super(psymetaclass, cls).__new__(cls, name, bases, dict)
|
||||
|
||||
psyobj = psymetaclass("psyobj", (), {})
|
||||
__metaclass__ = psymetaclass
|
||||
@@ -1,231 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco main functions.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco main functions.
|
||||
|
||||
Here are the routines that you can use from your applications.
|
||||
These are mostly interfaces to the C core, but they depend on
|
||||
the Python version.
|
||||
|
||||
You can use these functions from the 'psyco' module instead of
|
||||
'psyco.core', e.g.
|
||||
|
||||
import psyco
|
||||
psyco.log('/tmp/psyco.log')
|
||||
psyco.profile()
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
import _psyco
|
||||
import types
|
||||
from support import *
|
||||
|
||||
newfunction = types.FunctionType
|
||||
newinstancemethod = types.MethodType
|
||||
|
||||
|
||||
# Default charge profiler values
|
||||
default_watermark = 0.09 # between 0.0 (0%) and 1.0 (100%)
|
||||
default_halflife = 0.5 # seconds
|
||||
default_pollfreq_profile = 20 # Hz
|
||||
default_pollfreq_background = 100 # Hz -- a maximum for sleep's resolution
|
||||
default_parentframe = 0.25 # should not be more than 0.5 (50%)
|
||||
|
||||
|
||||
def full(memory=None, time=None, memorymax=None, timemax=None):
|
||||
"""Compile as much as possible.
|
||||
|
||||
Typical use is for small scripts performing intensive computations
|
||||
or string handling."""
|
||||
import profiler
|
||||
p = profiler.FullCompiler()
|
||||
p.run(memory, time, memorymax, timemax)
|
||||
|
||||
|
||||
def profile(watermark = default_watermark,
|
||||
halflife = default_halflife,
|
||||
pollfreq = default_pollfreq_profile,
|
||||
parentframe = default_parentframe,
|
||||
memory=None, time=None, memorymax=None, timemax=None):
|
||||
"""Turn on profiling.
|
||||
|
||||
The 'watermark' parameter controls how easily running functions will
|
||||
be compiled. The smaller the value, the more functions are compiled."""
|
||||
import profiler
|
||||
p = profiler.ActivePassiveProfiler(watermark, halflife,
|
||||
pollfreq, parentframe)
|
||||
p.run(memory, time, memorymax, timemax)
|
||||
|
||||
|
||||
def background(watermark = default_watermark,
|
||||
halflife = default_halflife,
|
||||
pollfreq = default_pollfreq_background,
|
||||
parentframe = default_parentframe,
|
||||
memory=None, time=None, memorymax=None, timemax=None):
|
||||
"""Turn on passive profiling.
|
||||
|
||||
This is a very lightweight mode in which only intensively computing
|
||||
functions can be detected. The smaller the 'watermark', the more functions
|
||||
are compiled."""
|
||||
import profiler
|
||||
p = profiler.PassiveProfiler(watermark, halflife, pollfreq, parentframe)
|
||||
p.run(memory, time, memorymax, timemax)
|
||||
|
||||
|
||||
def runonly(memory=None, time=None, memorymax=None, timemax=None):
|
||||
"""Nonprofiler.
|
||||
|
||||
XXX check if this is useful and document."""
|
||||
import profiler
|
||||
p = profiler.RunOnly()
|
||||
p.run(memory, time, memorymax, timemax)
|
||||
|
||||
|
||||
def stop():
|
||||
"""Turn off all automatic compilation. bind() calls remain in effect."""
|
||||
import profiler
|
||||
profiler.go([])
|
||||
|
||||
|
||||
def log(logfile='', mode='w', top=10):
|
||||
"""Enable logging to the given file.
|
||||
|
||||
If the file name is unspecified, a default name is built by appending
|
||||
a 'log-psyco' extension to the main script name.
|
||||
|
||||
Mode is 'a' to append to a possibly existing file or 'w' to overwrite
|
||||
an existing file. Note that the log file may grow quickly in 'a' mode."""
|
||||
import profiler, logger
|
||||
if not logfile:
|
||||
import os
|
||||
logfile, dummy = os.path.splitext(sys.argv[0])
|
||||
if os.path.basename(logfile):
|
||||
logfile += '.'
|
||||
logfile += 'log-psyco'
|
||||
if hasattr(_psyco, 'VERBOSE_LEVEL'):
|
||||
print >> sys.stderr, 'psyco: logging to', logfile
|
||||
# logger.current should be a real file object; subtle problems
|
||||
# will show up if its write() and flush() methods are written
|
||||
# in Python, as Psyco will invoke them while compiling.
|
||||
logger.current = open(logfile, mode)
|
||||
logger.print_charges = top
|
||||
profiler.logger = logger
|
||||
logger.writedate('Logging started')
|
||||
cannotcompile(logger.psycowrite)
|
||||
_psyco.statwrite(logger=logger.psycowrite)
|
||||
|
||||
|
||||
def bind(x, rec=None):
|
||||
"""Enable compilation of the given function, method, or class object.
|
||||
|
||||
If C is a class (or anything with a '__dict__' attribute), bind(C) will
|
||||
rebind all functions and methods found in C.__dict__ (which means, for
|
||||
classes, all methods defined in the class but not in its parents).
|
||||
|
||||
The optional second argument specifies the number of recursive
|
||||
compilation levels: all functions called by func are compiled
|
||||
up to the given depth of indirection."""
|
||||
if isinstance(x, types.MethodType):
|
||||
x = x.im_func
|
||||
if isinstance(x, types.FunctionType):
|
||||
if rec is None:
|
||||
x.func_code = _psyco.proxycode(x)
|
||||
else:
|
||||
x.func_code = _psyco.proxycode(x, rec)
|
||||
return
|
||||
if hasattr(x, '__dict__'):
|
||||
funcs = [o for o in x.__dict__.values()
|
||||
if isinstance(o, types.MethodType)
|
||||
or isinstance(o, types.FunctionType)]
|
||||
if not funcs:
|
||||
raise error, ("nothing bindable found in %s object" %
|
||||
type(x).__name__)
|
||||
for o in funcs:
|
||||
bind(o, rec)
|
||||
return
|
||||
raise TypeError, "cannot bind %s objects" % type(x).__name__
|
||||
|
||||
|
||||
def unbind(x):
|
||||
"""Reverse of bind()."""
|
||||
if isinstance(x, types.MethodType):
|
||||
x = x.im_func
|
||||
if isinstance(x, types.FunctionType):
|
||||
try:
|
||||
f = _psyco.unproxycode(x.func_code)
|
||||
except error:
|
||||
pass
|
||||
else:
|
||||
x.func_code = f.func_code
|
||||
return
|
||||
if hasattr(x, '__dict__'):
|
||||
for o in x.__dict__.values():
|
||||
if (isinstance(o, types.MethodType)
|
||||
or isinstance(o, types.FunctionType)):
|
||||
unbind(o)
|
||||
return
|
||||
raise TypeError, "cannot unbind %s objects" % type(x).__name__
|
||||
|
||||
|
||||
def proxy(x, rec=None):
|
||||
"""Return a Psyco-enabled copy of the function.
|
||||
|
||||
The original function is still available for non-compiled calls.
|
||||
The optional second argument specifies the number of recursive
|
||||
compilation levels: all functions called by func are compiled
|
||||
up to the given depth of indirection."""
|
||||
if isinstance(x, types.FunctionType):
|
||||
if rec is None:
|
||||
code = _psyco.proxycode(x)
|
||||
else:
|
||||
code = _psyco.proxycode(x, rec)
|
||||
return newfunction(code, x.func_globals, x.func_name)
|
||||
if isinstance(x, types.MethodType):
|
||||
p = proxy(x.im_func, rec)
|
||||
return newinstancemethod(p, x.im_self, x.im_class)
|
||||
raise TypeError, "cannot proxy %s objects" % type(x).__name__
|
||||
|
||||
|
||||
def unproxy(proxy):
|
||||
"""Return a new copy of the original function of method behind a proxy.
|
||||
The result behaves like the original function in that calling it
|
||||
does not trigger compilation nor execution of any compiled code."""
|
||||
if isinstance(proxy, types.FunctionType):
|
||||
return _psyco.unproxycode(proxy.func_code)
|
||||
if isinstance(proxy, types.MethodType):
|
||||
f = unproxy(proxy.im_func)
|
||||
return newinstancemethod(f, proxy.im_self, proxy.im_class)
|
||||
raise TypeError, "%s objects cannot be proxies" % type(proxy).__name__
|
||||
|
||||
|
||||
def cannotcompile(x):
|
||||
"""Instruct Psyco never to compile the given function, method
|
||||
or code object."""
|
||||
if isinstance(x, types.MethodType):
|
||||
x = x.im_func
|
||||
if isinstance(x, types.FunctionType):
|
||||
x = x.func_code
|
||||
if isinstance(x, types.CodeType):
|
||||
_psyco.cannotcompile(x)
|
||||
else:
|
||||
raise TypeError, "unexpected %s object" % type(x).__name__
|
||||
|
||||
|
||||
def dumpcodebuf():
|
||||
"""Write in file psyco.dump a copy of the emitted machine code,
|
||||
provided Psyco was compiled with a non-zero CODE_DUMP.
|
||||
See py-utils/httpxam.py to examine psyco.dump."""
|
||||
if hasattr(_psyco, 'dumpcodebuf'):
|
||||
_psyco.dumpcodebuf()
|
||||
|
||||
|
||||
###########################################################################
|
||||
# Psyco variables
|
||||
# error * the error raised by Psyco
|
||||
# warning * the warning raised by Psyco
|
||||
# __in_psyco__ * a new built-in variable which is always zero, but which
|
||||
# Psyco special-cases by returning 1 instead. So
|
||||
# __in_psyco__ can be used in a function to know if
|
||||
# that function is being executed by Psyco or not.
|
||||
@@ -1,133 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Support code for the 'psyco.compact' type.
|
||||
|
||||
from __future__ import generators
|
||||
|
||||
try:
|
||||
from UserDict import DictMixin
|
||||
except ImportError:
|
||||
|
||||
# backported from Python 2.3 to Python 2.2
|
||||
class DictMixin:
|
||||
# Mixin defining all dictionary methods for classes that already have
|
||||
# a minimum dictionary interface including getitem, setitem, delitem,
|
||||
# and keys. Without knowledge of the subclass constructor, the mixin
|
||||
# does not define __init__() or copy(). In addition to the four base
|
||||
# methods, progressively more efficiency comes with defining
|
||||
# __contains__(), __iter__(), and iteritems().
|
||||
|
||||
# second level definitions support higher levels
|
||||
def __iter__(self):
|
||||
for k in self.keys():
|
||||
yield k
|
||||
def has_key(self, key):
|
||||
try:
|
||||
value = self[key]
|
||||
except KeyError:
|
||||
return False
|
||||
return True
|
||||
def __contains__(self, key):
|
||||
return self.has_key(key)
|
||||
|
||||
# third level takes advantage of second level definitions
|
||||
def iteritems(self):
|
||||
for k in self:
|
||||
yield (k, self[k])
|
||||
def iterkeys(self):
|
||||
return self.__iter__()
|
||||
|
||||
# fourth level uses definitions from lower levels
|
||||
def itervalues(self):
|
||||
for _, v in self.iteritems():
|
||||
yield v
|
||||
def values(self):
|
||||
return [v for _, v in self.iteritems()]
|
||||
def items(self):
|
||||
return list(self.iteritems())
|
||||
def clear(self):
|
||||
for key in self.keys():
|
||||
del self[key]
|
||||
def setdefault(self, key, default):
|
||||
try:
|
||||
return self[key]
|
||||
except KeyError:
|
||||
self[key] = default
|
||||
return default
|
||||
def pop(self, key, *args):
|
||||
if len(args) > 1:
|
||||
raise TypeError, "pop expected at most 2 arguments, got "\
|
||||
+ repr(1 + len(args))
|
||||
try:
|
||||
value = self[key]
|
||||
except KeyError:
|
||||
if args:
|
||||
return args[0]
|
||||
raise
|
||||
del self[key]
|
||||
return value
|
||||
def popitem(self):
|
||||
try:
|
||||
k, v = self.iteritems().next()
|
||||
except StopIteration:
|
||||
raise KeyError, 'container is empty'
|
||||
del self[k]
|
||||
return (k, v)
|
||||
def update(self, other):
|
||||
# Make progressively weaker assumptions about "other"
|
||||
if hasattr(other, 'iteritems'): # iteritems saves memory and lookups
|
||||
for k, v in other.iteritems():
|
||||
self[k] = v
|
||||
elif hasattr(other, '__iter__'): # iter saves memory
|
||||
for k in other:
|
||||
self[k] = other[k]
|
||||
else:
|
||||
for k in other.keys():
|
||||
self[k] = other[k]
|
||||
def get(self, key, default=None):
|
||||
try:
|
||||
return self[key]
|
||||
except KeyError:
|
||||
return default
|
||||
def __repr__(self):
|
||||
return repr(dict(self.iteritems()))
|
||||
def __cmp__(self, other):
|
||||
if other is None:
|
||||
return 1
|
||||
if isinstance(other, DictMixin):
|
||||
other = dict(other.iteritems())
|
||||
return cmp(dict(self.iteritems()), other)
|
||||
def __len__(self):
|
||||
return len(self.keys())
|
||||
|
||||
###########################################################################
|
||||
|
||||
from _psyco import compact
|
||||
|
||||
|
||||
class compactdictproxy(DictMixin):
|
||||
|
||||
def __init__(self, ko):
|
||||
self._ko = ko # compact object of which 'self' is the dict
|
||||
|
||||
def __getitem__(self, key):
|
||||
return compact.__getslot__(self._ko, key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
compact.__setslot__(self._ko, key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
compact.__delslot__(self._ko, key)
|
||||
|
||||
def keys(self):
|
||||
return compact.__members__.__get__(self._ko)
|
||||
|
||||
def clear(self):
|
||||
keys = self.keys()
|
||||
keys.reverse()
|
||||
for key in keys:
|
||||
del self[key]
|
||||
|
||||
def __repr__(self):
|
||||
keys = ', '.join(self.keys())
|
||||
return '<compactdictproxy object {%s}>' % (keys,)
|
||||
@@ -1,96 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco logger.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco logger.
|
||||
|
||||
See log() in core.py.
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
|
||||
import _psyco
|
||||
from time import time, localtime, strftime
|
||||
|
||||
|
||||
current = None
|
||||
print_charges = 10
|
||||
dump_delay = 0.2
|
||||
dump_last = 0.0
|
||||
|
||||
def write(s, level):
|
||||
t = time()
|
||||
f = t-int(t)
|
||||
try:
|
||||
current.write("%s.%02d %-*s%s\n" % (
|
||||
strftime("%X", localtime(int(t))),
|
||||
int(f*100.0), 63-level, s,
|
||||
"%"*level))
|
||||
current.flush()
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
def psycowrite(s):
|
||||
t = time()
|
||||
f = t-int(t)
|
||||
try:
|
||||
current.write("%s.%02d %-*s%s\n" % (
|
||||
strftime("%X", localtime(int(t))),
|
||||
int(f*100.0), 60, s.strip(),
|
||||
"% %"))
|
||||
current.flush()
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
##def writelines(lines, level=0):
|
||||
## if lines:
|
||||
## t = time()
|
||||
## f = t-int(t)
|
||||
## timedesc = strftime("%x %X", localtime(int(t)))
|
||||
## print >> current, "%s.%03d %-*s %s" % (
|
||||
## timedesc, int(f*1000),
|
||||
## 50-level, lines[0],
|
||||
## "+"*level)
|
||||
## timedesc = " " * (len(timedesc)+5)
|
||||
## for line in lines[1:]:
|
||||
## print >> current, timedesc, line
|
||||
|
||||
def writememory():
|
||||
write("memory usage: %d+ kb" % _psyco.memory(), 1)
|
||||
|
||||
def dumpcharges():
|
||||
global dump_last
|
||||
if print_charges:
|
||||
t = time()
|
||||
if not (dump_last <= t < dump_last+dump_delay):
|
||||
if t <= dump_last+1.5*dump_delay:
|
||||
dump_last += dump_delay
|
||||
else:
|
||||
dump_last = t
|
||||
#write("%s: charges:" % who, 0)
|
||||
lst = _psyco.stattop(print_charges)
|
||||
if lst:
|
||||
f = t-int(t)
|
||||
lines = ["%s.%02d ______\n" % (
|
||||
strftime("%X", localtime(int(t))),
|
||||
int(f*100.0))]
|
||||
i = 1
|
||||
for co, charge in lst:
|
||||
detail = co.co_filename
|
||||
if len(detail) > 19:
|
||||
detail = '...' + detail[-17:]
|
||||
lines.append(" #%-3d |%4.1f %%| %-26s%20s:%d\n" %
|
||||
(i, charge*100.0, co.co_name, detail,
|
||||
co.co_firstlineno))
|
||||
i += 1
|
||||
current.writelines(lines)
|
||||
current.flush()
|
||||
|
||||
def writefinalstats():
|
||||
dumpcharges()
|
||||
writememory()
|
||||
writedate("program exit")
|
||||
|
||||
def writedate(msg):
|
||||
write('%s, %s' % (msg, strftime("%x")), 20)
|
||||
@@ -1,379 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco profiler (Python part).
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco profiler (Python part).
|
||||
|
||||
The implementation of the non-time-critical parts of the profiler.
|
||||
See profile() and full() in core.py for the easy interface.
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
import _psyco
|
||||
from support import *
|
||||
import math, time, types, atexit
|
||||
now = time.time
|
||||
try:
|
||||
import thread
|
||||
except ImportError:
|
||||
import dummy_thread as thread
|
||||
|
||||
|
||||
# current profiler instance
|
||||
current = None
|
||||
|
||||
# enabled profilers, in order of priority
|
||||
profilers = []
|
||||
|
||||
# logger module (when enabled by core.log())
|
||||
logger = None
|
||||
|
||||
# a lock for a thread-safe go()
|
||||
go_lock = thread.allocate_lock()
|
||||
|
||||
def go(stop=0):
|
||||
# run the highest-priority profiler in 'profilers'
|
||||
global current
|
||||
go_lock.acquire()
|
||||
try:
|
||||
prev = current
|
||||
if stop:
|
||||
del profilers[:]
|
||||
if prev:
|
||||
if profilers and profilers[0] is prev:
|
||||
return # best profiler already running
|
||||
prev.stop()
|
||||
current = None
|
||||
for p in profilers[:]:
|
||||
if p.start():
|
||||
current = p
|
||||
if logger: # and p is not prev:
|
||||
logger.write("%s: starting" % p.__class__.__name__, 5)
|
||||
return
|
||||
finally:
|
||||
go_lock.release()
|
||||
# no profiler is running now
|
||||
if stop:
|
||||
if logger:
|
||||
logger.writefinalstats()
|
||||
else:
|
||||
tag2bind()
|
||||
|
||||
atexit.register(go, 1)
|
||||
|
||||
|
||||
def buildfncache(globals, cache):
|
||||
if hasattr(types.IntType, '__dict__'):
|
||||
clstypes = (types.ClassType, types.TypeType)
|
||||
else:
|
||||
clstypes = types.ClassType
|
||||
for x in globals.values():
|
||||
if isinstance(x, types.MethodType):
|
||||
x = x.im_func
|
||||
if isinstance(x, types.FunctionType):
|
||||
cache[x.func_code] = x, ''
|
||||
elif isinstance(x, clstypes):
|
||||
for y in x.__dict__.values():
|
||||
if isinstance(y, types.MethodType):
|
||||
y = y.im_func
|
||||
if isinstance(y, types.FunctionType):
|
||||
cache[y.func_code] = y, x.__name__
|
||||
|
||||
# code-to-function mapping (cache)
|
||||
function_cache = {}
|
||||
|
||||
def trytobind(co, globals, log=1):
|
||||
try:
|
||||
f, clsname = function_cache[co]
|
||||
except KeyError:
|
||||
buildfncache(globals, function_cache)
|
||||
try:
|
||||
f, clsname = function_cache[co]
|
||||
except KeyError:
|
||||
if logger:
|
||||
logger.write('warning: cannot find function %s in %s' %
|
||||
(co.co_name, globals.get('__name__', '?')), 3)
|
||||
return # give up
|
||||
if logger and log:
|
||||
modulename = globals.get('__name__', '?')
|
||||
if clsname:
|
||||
modulename += '.' + clsname
|
||||
logger.write('bind function: %s.%s' % (modulename, co.co_name), 1)
|
||||
f.func_code = _psyco.proxycode(f)
|
||||
|
||||
|
||||
# the list of code objects that have been tagged
|
||||
tagged_codes = []
|
||||
|
||||
def tag(co, globals):
|
||||
if logger:
|
||||
try:
|
||||
f, clsname = function_cache[co]
|
||||
except KeyError:
|
||||
buildfncache(globals, function_cache)
|
||||
try:
|
||||
f, clsname = function_cache[co]
|
||||
except KeyError:
|
||||
clsname = '' # give up
|
||||
modulename = globals.get('__name__', '?')
|
||||
if clsname:
|
||||
modulename += '.' + clsname
|
||||
logger.write('tag function: %s.%s' % (modulename, co.co_name), 1)
|
||||
tagged_codes.append((co, globals))
|
||||
_psyco.turbo_frame(co)
|
||||
_psyco.turbo_code(co)
|
||||
|
||||
def tag2bind():
|
||||
if tagged_codes:
|
||||
if logger:
|
||||
logger.write('profiling stopped, binding %d functions' %
|
||||
len(tagged_codes), 2)
|
||||
for co, globals in tagged_codes:
|
||||
trytobind(co, globals, 0)
|
||||
function_cache.clear()
|
||||
del tagged_codes[:]
|
||||
|
||||
|
||||
class Profiler:
|
||||
MemoryTimerResolution = 0.103
|
||||
|
||||
def run(self, memory, time, memorymax, timemax):
|
||||
self.memory = memory
|
||||
self.memorymax = memorymax
|
||||
self.time = time
|
||||
if timemax is None:
|
||||
self.endtime = None
|
||||
else:
|
||||
self.endtime = now() + timemax
|
||||
self.alarms = []
|
||||
profilers.append(self)
|
||||
go()
|
||||
|
||||
def start(self):
|
||||
curmem = _psyco.memory()
|
||||
memlimits = []
|
||||
if self.memorymax is not None:
|
||||
if curmem >= self.memorymax:
|
||||
if logger:
|
||||
logger.writememory()
|
||||
return self.limitreached('memorymax')
|
||||
memlimits.append(self.memorymax)
|
||||
if self.memory is not None:
|
||||
if self.memory <= 0:
|
||||
if logger:
|
||||
logger.writememory()
|
||||
return self.limitreached('memory')
|
||||
memlimits.append(curmem + self.memory)
|
||||
self.memory_at_start = curmem
|
||||
|
||||
curtime = now()
|
||||
timelimits = []
|
||||
if self.endtime is not None:
|
||||
if curtime >= self.endtime:
|
||||
return self.limitreached('timemax')
|
||||
timelimits.append(self.endtime - curtime)
|
||||
if self.time is not None:
|
||||
if self.time <= 0.0:
|
||||
return self.limitreached('time')
|
||||
timelimits.append(self.time)
|
||||
self.time_at_start = curtime
|
||||
|
||||
try:
|
||||
self.do_start()
|
||||
except error, e:
|
||||
if logger:
|
||||
logger.write('%s: disabled by psyco.error:' % (
|
||||
self.__class__.__name__), 4)
|
||||
logger.write(' %s' % str(e), 3)
|
||||
return 0
|
||||
|
||||
if memlimits:
|
||||
self.memlimits_args = (time.sleep, (self.MemoryTimerResolution,),
|
||||
self.check_memory, (min(memlimits),))
|
||||
self.alarms.append(_psyco.alarm(*self.memlimits_args))
|
||||
if timelimits:
|
||||
self.alarms.append(_psyco.alarm(time.sleep, (min(timelimits),),
|
||||
self.time_out))
|
||||
return 1
|
||||
|
||||
def stop(self):
|
||||
for alarm in self.alarms:
|
||||
alarm.stop(0)
|
||||
for alarm in self.alarms:
|
||||
alarm.stop(1) # wait for parallel threads to stop
|
||||
del self.alarms[:]
|
||||
if self.time is not None:
|
||||
self.time -= now() - self.time_at_start
|
||||
if self.memory is not None:
|
||||
self.memory -= _psyco.memory() - self.memory_at_start
|
||||
|
||||
try:
|
||||
self.do_stop()
|
||||
except error:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def check_memory(self, limit):
|
||||
if _psyco.memory() < limit:
|
||||
return self.memlimits_args
|
||||
go()
|
||||
|
||||
def time_out(self):
|
||||
self.time = 0.0
|
||||
go()
|
||||
|
||||
def limitreached(self, limitname):
|
||||
try:
|
||||
profilers.remove(self)
|
||||
except ValueError:
|
||||
pass
|
||||
if logger:
|
||||
logger.write('%s: disabled (%s limit reached)' % (
|
||||
self.__class__.__name__, limitname), 4)
|
||||
return 0
|
||||
|
||||
|
||||
class FullCompiler(Profiler):
|
||||
|
||||
def do_start(self):
|
||||
_psyco.profiling('f')
|
||||
|
||||
def do_stop(self):
|
||||
_psyco.profiling('.')
|
||||
|
||||
|
||||
class RunOnly(Profiler):
|
||||
|
||||
def do_start(self):
|
||||
_psyco.profiling('n')
|
||||
|
||||
def do_stop(self):
|
||||
_psyco.profiling('.')
|
||||
|
||||
|
||||
class ChargeProfiler(Profiler):
|
||||
|
||||
def __init__(self, watermark, parentframe):
|
||||
self.watermark = watermark
|
||||
self.parent2 = parentframe * 2.0
|
||||
self.lock = thread.allocate_lock()
|
||||
|
||||
def init_charges(self):
|
||||
_psyco.statwrite(watermark = self.watermark,
|
||||
parent2 = self.parent2)
|
||||
|
||||
def do_stop(self):
|
||||
_psyco.profiling('.')
|
||||
_psyco.statwrite(callback = None)
|
||||
|
||||
|
||||
class ActiveProfiler(ChargeProfiler):
|
||||
|
||||
def active_start(self):
|
||||
_psyco.profiling('p')
|
||||
|
||||
def do_start(self):
|
||||
self.init_charges()
|
||||
self.active_start()
|
||||
_psyco.statwrite(callback = self.charge_callback)
|
||||
|
||||
def charge_callback(self, frame, charge):
|
||||
tag(frame.f_code, frame.f_globals)
|
||||
|
||||
|
||||
class PassiveProfiler(ChargeProfiler):
|
||||
|
||||
initial_charge_unit = _psyco.statread('unit')
|
||||
reset_stats_after = 120 # half-lives (maximum 200!)
|
||||
reset_limit = initial_charge_unit * (2.0 ** reset_stats_after)
|
||||
|
||||
def __init__(self, watermark, halflife, pollfreq, parentframe):
|
||||
ChargeProfiler.__init__(self, watermark, parentframe)
|
||||
self.pollfreq = pollfreq
|
||||
# self.progress is slightly more than 1.0, and computed so that
|
||||
# do_profile() will double the change_unit every 'halflife' seconds.
|
||||
self.progress = 2.0 ** (1.0 / (halflife * pollfreq))
|
||||
|
||||
def reset(self):
|
||||
_psyco.statwrite(unit = self.initial_charge_unit, callback = None)
|
||||
_psyco.statreset()
|
||||
if logger:
|
||||
logger.write("%s: resetting stats" % self.__class__.__name__, 1)
|
||||
|
||||
def passive_start(self):
|
||||
self.passivealarm_args = (time.sleep, (1.0 / self.pollfreq,),
|
||||
self.do_profile)
|
||||
self.alarms.append(_psyco.alarm(*self.passivealarm_args))
|
||||
|
||||
def do_start(self):
|
||||
tag2bind()
|
||||
self.init_charges()
|
||||
self.passive_start()
|
||||
|
||||
def do_profile(self):
|
||||
_psyco.statcollect()
|
||||
if logger:
|
||||
logger.dumpcharges()
|
||||
nunit = _psyco.statread('unit') * self.progress
|
||||
if nunit > self.reset_limit:
|
||||
self.reset()
|
||||
else:
|
||||
_psyco.statwrite(unit = nunit, callback = self.charge_callback)
|
||||
return self.passivealarm_args
|
||||
|
||||
def charge_callback(self, frame, charge):
|
||||
trytobind(frame.f_code, frame.f_globals)
|
||||
|
||||
|
||||
class ActivePassiveProfiler(PassiveProfiler, ActiveProfiler):
|
||||
|
||||
def do_start(self):
|
||||
self.init_charges()
|
||||
self.active_start()
|
||||
self.passive_start()
|
||||
|
||||
def charge_callback(self, frame, charge):
|
||||
tag(frame.f_code, frame.f_globals)
|
||||
|
||||
|
||||
|
||||
#
|
||||
# we register our own version of sys.settrace(), sys.setprofile()
|
||||
# and thread.start_new_thread().
|
||||
#
|
||||
|
||||
def psyco_settrace(*args, **kw):
|
||||
"This is the Psyco-aware version of sys.settrace()."
|
||||
result = original_settrace(*args, **kw)
|
||||
go()
|
||||
return result
|
||||
|
||||
def psyco_setprofile(*args, **kw):
|
||||
"This is the Psyco-aware version of sys.setprofile()."
|
||||
result = original_setprofile(*args, **kw)
|
||||
go()
|
||||
return result
|
||||
|
||||
def psyco_thread_stub(callable, args, kw):
|
||||
_psyco.statcollect()
|
||||
if kw is None:
|
||||
return callable(*args)
|
||||
else:
|
||||
return callable(*args, **kw)
|
||||
|
||||
def psyco_start_new_thread(callable, args, kw=None):
|
||||
"This is the Psyco-aware version of thread.start_new_thread()."
|
||||
return original_start_new_thread(psyco_thread_stub, (callable, args, kw))
|
||||
|
||||
original_settrace = sys.settrace
|
||||
original_setprofile = sys.setprofile
|
||||
original_start_new_thread = thread.start_new_thread
|
||||
sys.settrace = psyco_settrace
|
||||
sys.setprofile = psyco_setprofile
|
||||
thread.start_new_thread = psyco_start_new_thread
|
||||
# hack to patch threading._start_new_thread if the module is
|
||||
# already loaded
|
||||
if ('threading' in sys.modules and
|
||||
hasattr(sys.modules['threading'], '_start_new_thread')):
|
||||
sys.modules['threading']._start_new_thread = psyco_start_new_thread
|
||||
@@ -1,191 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco general support module.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco general support module.
|
||||
|
||||
For internal use.
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
import sys, _psyco, __builtin__
|
||||
|
||||
error = _psyco.error
|
||||
class warning(Warning):
|
||||
pass
|
||||
|
||||
_psyco.NoLocalsWarning = warning
|
||||
|
||||
def warn(msg):
|
||||
from warnings import warn
|
||||
warn(msg, warning, stacklevel=2)
|
||||
|
||||
#
|
||||
# Version checks
|
||||
#
|
||||
__version__ = 0x010600f0
|
||||
if _psyco.PSYVER != __version__:
|
||||
raise error, "version mismatch between Psyco parts, reinstall it"
|
||||
|
||||
version_info = (__version__ >> 24,
|
||||
(__version__ >> 16) & 0xff,
|
||||
(__version__ >> 8) & 0xff,
|
||||
{0xa0: 'alpha',
|
||||
0xb0: 'beta',
|
||||
0xc0: 'candidate',
|
||||
0xf0: 'final'}[__version__ & 0xf0],
|
||||
__version__ & 0xf)
|
||||
|
||||
|
||||
VERSION_LIMITS = [0x02020200, # 2.2.2
|
||||
0x02030000, # 2.3
|
||||
0x02040000] # 2.4
|
||||
|
||||
if ([v for v in VERSION_LIMITS if v <= sys.hexversion] !=
|
||||
[v for v in VERSION_LIMITS if v <= _psyco.PYVER ]):
|
||||
if sys.hexversion < VERSION_LIMITS[0]:
|
||||
warn("Psyco requires Python version 2.2.2 or later")
|
||||
else:
|
||||
warn("Psyco version does not match Python version. "
|
||||
"Psyco must be updated or recompiled")
|
||||
|
||||
|
||||
if hasattr(_psyco, 'ALL_CHECKS') and hasattr(_psyco, 'VERBOSE_LEVEL'):
|
||||
print >> sys.stderr, ('psyco: running in debugging mode on %s' %
|
||||
_psyco.PROCESSOR)
|
||||
|
||||
|
||||
###########################################################################
|
||||
# sys._getframe() gives strange results on a mixed Psyco- and Python-style
|
||||
# stack frame. Psyco provides a replacement that partially emulates Python
|
||||
# frames from Psyco frames. The new sys._getframe() may return objects of
|
||||
# a custom "Psyco frame" type, which is a subtype of the normal frame type.
|
||||
#
|
||||
# The same problems require some other built-in functions to be replaced
|
||||
# as well. Note that the local variables are not available in any
|
||||
# dictionary with Psyco.
|
||||
|
||||
|
||||
class Frame:
|
||||
pass
|
||||
|
||||
|
||||
class PythonFrame(Frame):
|
||||
|
||||
def __init__(self, frame):
|
||||
self.__dict__.update({
|
||||
'_frame': frame,
|
||||
})
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'f_back':
|
||||
try:
|
||||
result = embedframe(_psyco.getframe(self._frame))
|
||||
except ValueError:
|
||||
result = None
|
||||
except error:
|
||||
warn("f_back is skipping dead Psyco frames")
|
||||
result = self._frame.f_back
|
||||
self.__dict__['f_back'] = result
|
||||
return result
|
||||
else:
|
||||
return getattr(self._frame, attr)
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
setattr(self._frame, attr, value)
|
||||
|
||||
def __delattr__(self, attr):
|
||||
delattr(self._frame, attr)
|
||||
|
||||
|
||||
class PsycoFrame(Frame):
|
||||
|
||||
def __init__(self, tag):
|
||||
self.__dict__.update({
|
||||
'_tag' : tag,
|
||||
'f_code' : tag[0],
|
||||
'f_globals': tag[1],
|
||||
})
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'f_back':
|
||||
try:
|
||||
result = embedframe(_psyco.getframe(self._tag))
|
||||
except ValueError:
|
||||
result = None
|
||||
elif attr == 'f_lineno':
|
||||
result = self.f_code.co_firstlineno # better than nothing
|
||||
elif attr == 'f_builtins':
|
||||
result = self.f_globals['__builtins__']
|
||||
elif attr == 'f_restricted':
|
||||
result = self.f_builtins is not __builtins__
|
||||
elif attr == 'f_locals':
|
||||
raise AttributeError, ("local variables of functions run by Psyco "
|
||||
"cannot be accessed in any way, sorry")
|
||||
else:
|
||||
raise AttributeError, ("emulated Psyco frames have "
|
||||
"no '%s' attribute" % attr)
|
||||
self.__dict__[attr] = result
|
||||
return result
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
raise AttributeError, "Psyco frame objects are read-only"
|
||||
|
||||
def __delattr__(self, attr):
|
||||
if attr == 'f_trace':
|
||||
# for bdb which relies on CPython frames exhibiting a slightly
|
||||
# buggy behavior: you can 'del f.f_trace' as often as you like
|
||||
# even without having set it previously.
|
||||
return
|
||||
raise AttributeError, "Psyco frame objects are read-only"
|
||||
|
||||
|
||||
def embedframe(result):
|
||||
if type(result) is type(()):
|
||||
return PsycoFrame(result)
|
||||
else:
|
||||
return PythonFrame(result)
|
||||
|
||||
def _getframe(depth=0):
|
||||
"""Return a frame object from the call stack. This is a replacement for
|
||||
sys._getframe() which is aware of Psyco frames.
|
||||
|
||||
The returned objects are instances of either PythonFrame or PsycoFrame
|
||||
instead of being real Python-level frame object, so that they can emulate
|
||||
the common attributes of frame objects.
|
||||
|
||||
The original sys._getframe() ignoring Psyco frames altogether is stored in
|
||||
psyco._getrealframe(). See also psyco._getemulframe()."""
|
||||
# 'depth+1' to account for this _getframe() Python function
|
||||
return embedframe(_psyco.getframe(depth+1))
|
||||
|
||||
def _getemulframe(depth=0):
|
||||
"""As _getframe(), but the returned objects are real Python frame objects
|
||||
emulating Psyco frames. Some of their attributes can be wrong or missing,
|
||||
however."""
|
||||
# 'depth+1' to account for this _getemulframe() Python function
|
||||
return _psyco.getframe(depth+1, 1)
|
||||
|
||||
def patch(name, module=__builtin__):
|
||||
f = getattr(_psyco, name)
|
||||
org = getattr(module, name)
|
||||
if org is not f:
|
||||
setattr(module, name, f)
|
||||
setattr(_psyco, 'original_' + name, org)
|
||||
|
||||
_getrealframe = sys._getframe
|
||||
sys._getframe = _getframe
|
||||
patch('globals')
|
||||
patch('eval')
|
||||
patch('execfile')
|
||||
patch('locals')
|
||||
patch('vars')
|
||||
patch('dir')
|
||||
patch('input')
|
||||
_psyco.original_raw_input = raw_input
|
||||
__builtin__.__in_psyco__ = 0==1 # False
|
||||
|
||||
if hasattr(_psyco, 'compact'):
|
||||
import kdictproxy
|
||||
_psyco.compactdictproxy = kdictproxy.compactdictproxy
|
||||
@@ -1,54 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco top-level file of the Psyco package.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco -- the Python Specializing Compiler.
|
||||
|
||||
Typical usage: add the following lines to your application's main module,
|
||||
preferably after the other imports:
|
||||
|
||||
try:
|
||||
import psyco
|
||||
psyco.full()
|
||||
except ImportError:
|
||||
print 'Psyco not installed, the program will just run slower'
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
|
||||
#
|
||||
# This module is present to make 'psyco' a package and to
|
||||
# publish the main functions and variables.
|
||||
#
|
||||
# More documentation can be found in core.py.
|
||||
#
|
||||
|
||||
|
||||
# Try to import the dynamic-loading _psyco and report errors
|
||||
try:
|
||||
import _psyco
|
||||
except ImportError, e:
|
||||
extramsg = ''
|
||||
import sys, imp
|
||||
try:
|
||||
file, filename, (suffix, mode, type) = imp.find_module('_psyco', __path__)
|
||||
except ImportError:
|
||||
ext = [suffix for suffix, mode, type in imp.get_suffixes()
|
||||
if type == imp.C_EXTENSION]
|
||||
if ext:
|
||||
extramsg = (" (cannot locate the compiled extension '_psyco%s' "
|
||||
"in the package path '%s')" % (ext[0], '; '.join(__path__)))
|
||||
else:
|
||||
extramsg = (" (check that the compiled extension '%s' is for "
|
||||
"the correct Python version; this is Python %s)" %
|
||||
(filename, sys.version.split()[0]))
|
||||
raise ImportError, str(e) + extramsg
|
||||
|
||||
# Publish important data by importing them in the package
|
||||
from support import __version__, error, warning, _getrealframe, _getemulframe
|
||||
from support import version_info, __version__ as hexversion
|
||||
from core import full, profile, background, runonly, stop, cannotcompile
|
||||
from core import log, bind, unbind, proxy, unproxy, dumpcodebuf
|
||||
from _psyco import setfilter
|
||||
from _psyco import compact, compacttype
|
||||
@@ -1,42 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco class support module.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco class support module.
|
||||
|
||||
'psyco.classes.psyobj' is an alternate Psyco-optimized root for classes.
|
||||
Any class inheriting from it or using the metaclass '__metaclass__' might
|
||||
get optimized specifically for Psyco. It is equivalent to call
|
||||
psyco.bind() on the class object after its creation.
|
||||
|
||||
Importing everything from psyco.classes in a module will import the
|
||||
'__metaclass__' name, so all classes defined after a
|
||||
|
||||
from psyco.classes import *
|
||||
|
||||
will automatically use the Psyco-optimized metaclass.
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
__all__ = ['psyobj', 'psymetaclass', '__metaclass__']
|
||||
|
||||
|
||||
from _psyco import compacttype
|
||||
import core
|
||||
from types import FunctionType
|
||||
|
||||
class psymetaclass(compacttype):
|
||||
"Psyco-optimized meta-class. Turns all methods into Psyco proxies."
|
||||
|
||||
def __new__(cls, name, bases, dict):
|
||||
bindlist = dict.get('__psyco__bind__')
|
||||
if bindlist is None:
|
||||
bindlist = [key for key, value in dict.items()
|
||||
if isinstance(value, FunctionType)]
|
||||
for attr in bindlist:
|
||||
dict[attr] = core.proxy(dict[attr])
|
||||
return super(psymetaclass, cls).__new__(cls, name, bases, dict)
|
||||
|
||||
psyobj = psymetaclass("psyobj", (), {})
|
||||
__metaclass__ = psymetaclass
|
||||
@@ -1,231 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco main functions.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco main functions.
|
||||
|
||||
Here are the routines that you can use from your applications.
|
||||
These are mostly interfaces to the C core, but they depend on
|
||||
the Python version.
|
||||
|
||||
You can use these functions from the 'psyco' module instead of
|
||||
'psyco.core', e.g.
|
||||
|
||||
import psyco
|
||||
psyco.log('/tmp/psyco.log')
|
||||
psyco.profile()
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
import _psyco
|
||||
import types
|
||||
from support import *
|
||||
|
||||
newfunction = types.FunctionType
|
||||
newinstancemethod = types.MethodType
|
||||
|
||||
|
||||
# Default charge profiler values
|
||||
default_watermark = 0.09 # between 0.0 (0%) and 1.0 (100%)
|
||||
default_halflife = 0.5 # seconds
|
||||
default_pollfreq_profile = 20 # Hz
|
||||
default_pollfreq_background = 100 # Hz -- a maximum for sleep's resolution
|
||||
default_parentframe = 0.25 # should not be more than 0.5 (50%)
|
||||
|
||||
|
||||
def full(memory=None, time=None, memorymax=None, timemax=None):
|
||||
"""Compile as much as possible.
|
||||
|
||||
Typical use is for small scripts performing intensive computations
|
||||
or string handling."""
|
||||
import profiler
|
||||
p = profiler.FullCompiler()
|
||||
p.run(memory, time, memorymax, timemax)
|
||||
|
||||
|
||||
def profile(watermark = default_watermark,
|
||||
halflife = default_halflife,
|
||||
pollfreq = default_pollfreq_profile,
|
||||
parentframe = default_parentframe,
|
||||
memory=None, time=None, memorymax=None, timemax=None):
|
||||
"""Turn on profiling.
|
||||
|
||||
The 'watermark' parameter controls how easily running functions will
|
||||
be compiled. The smaller the value, the more functions are compiled."""
|
||||
import profiler
|
||||
p = profiler.ActivePassiveProfiler(watermark, halflife,
|
||||
pollfreq, parentframe)
|
||||
p.run(memory, time, memorymax, timemax)
|
||||
|
||||
|
||||
def background(watermark = default_watermark,
|
||||
halflife = default_halflife,
|
||||
pollfreq = default_pollfreq_background,
|
||||
parentframe = default_parentframe,
|
||||
memory=None, time=None, memorymax=None, timemax=None):
|
||||
"""Turn on passive profiling.
|
||||
|
||||
This is a very lightweight mode in which only intensively computing
|
||||
functions can be detected. The smaller the 'watermark', the more functions
|
||||
are compiled."""
|
||||
import profiler
|
||||
p = profiler.PassiveProfiler(watermark, halflife, pollfreq, parentframe)
|
||||
p.run(memory, time, memorymax, timemax)
|
||||
|
||||
|
||||
def runonly(memory=None, time=None, memorymax=None, timemax=None):
|
||||
"""Nonprofiler.
|
||||
|
||||
XXX check if this is useful and document."""
|
||||
import profiler
|
||||
p = profiler.RunOnly()
|
||||
p.run(memory, time, memorymax, timemax)
|
||||
|
||||
|
||||
def stop():
|
||||
"""Turn off all automatic compilation. bind() calls remain in effect."""
|
||||
import profiler
|
||||
profiler.go([])
|
||||
|
||||
|
||||
def log(logfile='', mode='w', top=10):
|
||||
"""Enable logging to the given file.
|
||||
|
||||
If the file name is unspecified, a default name is built by appending
|
||||
a 'log-psyco' extension to the main script name.
|
||||
|
||||
Mode is 'a' to append to a possibly existing file or 'w' to overwrite
|
||||
an existing file. Note that the log file may grow quickly in 'a' mode."""
|
||||
import profiler, logger
|
||||
if not logfile:
|
||||
import os
|
||||
logfile, dummy = os.path.splitext(sys.argv[0])
|
||||
if os.path.basename(logfile):
|
||||
logfile += '.'
|
||||
logfile += 'log-psyco'
|
||||
if hasattr(_psyco, 'VERBOSE_LEVEL'):
|
||||
print >> sys.stderr, 'psyco: logging to', logfile
|
||||
# logger.current should be a real file object; subtle problems
|
||||
# will show up if its write() and flush() methods are written
|
||||
# in Python, as Psyco will invoke them while compiling.
|
||||
logger.current = open(logfile, mode)
|
||||
logger.print_charges = top
|
||||
profiler.logger = logger
|
||||
logger.writedate('Logging started')
|
||||
cannotcompile(logger.psycowrite)
|
||||
_psyco.statwrite(logger=logger.psycowrite)
|
||||
|
||||
|
||||
def bind(x, rec=None):
|
||||
"""Enable compilation of the given function, method, or class object.
|
||||
|
||||
If C is a class (or anything with a '__dict__' attribute), bind(C) will
|
||||
rebind all functions and methods found in C.__dict__ (which means, for
|
||||
classes, all methods defined in the class but not in its parents).
|
||||
|
||||
The optional second argument specifies the number of recursive
|
||||
compilation levels: all functions called by func are compiled
|
||||
up to the given depth of indirection."""
|
||||
if isinstance(x, types.MethodType):
|
||||
x = x.im_func
|
||||
if isinstance(x, types.FunctionType):
|
||||
if rec is None:
|
||||
x.func_code = _psyco.proxycode(x)
|
||||
else:
|
||||
x.func_code = _psyco.proxycode(x, rec)
|
||||
return
|
||||
if hasattr(x, '__dict__'):
|
||||
funcs = [o for o in x.__dict__.values()
|
||||
if isinstance(o, types.MethodType)
|
||||
or isinstance(o, types.FunctionType)]
|
||||
if not funcs:
|
||||
raise error, ("nothing bindable found in %s object" %
|
||||
type(x).__name__)
|
||||
for o in funcs:
|
||||
bind(o, rec)
|
||||
return
|
||||
raise TypeError, "cannot bind %s objects" % type(x).__name__
|
||||
|
||||
|
||||
def unbind(x):
|
||||
"""Reverse of bind()."""
|
||||
if isinstance(x, types.MethodType):
|
||||
x = x.im_func
|
||||
if isinstance(x, types.FunctionType):
|
||||
try:
|
||||
f = _psyco.unproxycode(x.func_code)
|
||||
except error:
|
||||
pass
|
||||
else:
|
||||
x.func_code = f.func_code
|
||||
return
|
||||
if hasattr(x, '__dict__'):
|
||||
for o in x.__dict__.values():
|
||||
if (isinstance(o, types.MethodType)
|
||||
or isinstance(o, types.FunctionType)):
|
||||
unbind(o)
|
||||
return
|
||||
raise TypeError, "cannot unbind %s objects" % type(x).__name__
|
||||
|
||||
|
||||
def proxy(x, rec=None):
|
||||
"""Return a Psyco-enabled copy of the function.
|
||||
|
||||
The original function is still available for non-compiled calls.
|
||||
The optional second argument specifies the number of recursive
|
||||
compilation levels: all functions called by func are compiled
|
||||
up to the given depth of indirection."""
|
||||
if isinstance(x, types.FunctionType):
|
||||
if rec is None:
|
||||
code = _psyco.proxycode(x)
|
||||
else:
|
||||
code = _psyco.proxycode(x, rec)
|
||||
return newfunction(code, x.func_globals, x.func_name)
|
||||
if isinstance(x, types.MethodType):
|
||||
p = proxy(x.im_func, rec)
|
||||
return newinstancemethod(p, x.im_self, x.im_class)
|
||||
raise TypeError, "cannot proxy %s objects" % type(x).__name__
|
||||
|
||||
|
||||
def unproxy(proxy):
|
||||
"""Return a new copy of the original function of method behind a proxy.
|
||||
The result behaves like the original function in that calling it
|
||||
does not trigger compilation nor execution of any compiled code."""
|
||||
if isinstance(proxy, types.FunctionType):
|
||||
return _psyco.unproxycode(proxy.func_code)
|
||||
if isinstance(proxy, types.MethodType):
|
||||
f = unproxy(proxy.im_func)
|
||||
return newinstancemethod(f, proxy.im_self, proxy.im_class)
|
||||
raise TypeError, "%s objects cannot be proxies" % type(proxy).__name__
|
||||
|
||||
|
||||
def cannotcompile(x):
|
||||
"""Instruct Psyco never to compile the given function, method
|
||||
or code object."""
|
||||
if isinstance(x, types.MethodType):
|
||||
x = x.im_func
|
||||
if isinstance(x, types.FunctionType):
|
||||
x = x.func_code
|
||||
if isinstance(x, types.CodeType):
|
||||
_psyco.cannotcompile(x)
|
||||
else:
|
||||
raise TypeError, "unexpected %s object" % type(x).__name__
|
||||
|
||||
|
||||
def dumpcodebuf():
|
||||
"""Write in file psyco.dump a copy of the emitted machine code,
|
||||
provided Psyco was compiled with a non-zero CODE_DUMP.
|
||||
See py-utils/httpxam.py to examine psyco.dump."""
|
||||
if hasattr(_psyco, 'dumpcodebuf'):
|
||||
_psyco.dumpcodebuf()
|
||||
|
||||
|
||||
###########################################################################
|
||||
# Psyco variables
|
||||
# error * the error raised by Psyco
|
||||
# warning * the warning raised by Psyco
|
||||
# __in_psyco__ * a new built-in variable which is always zero, but which
|
||||
# Psyco special-cases by returning 1 instead. So
|
||||
# __in_psyco__ can be used in a function to know if
|
||||
# that function is being executed by Psyco or not.
|
||||
@@ -1,133 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Support code for the 'psyco.compact' type.
|
||||
|
||||
from __future__ import generators
|
||||
|
||||
try:
|
||||
from UserDict import DictMixin
|
||||
except ImportError:
|
||||
|
||||
# backported from Python 2.3 to Python 2.2
|
||||
class DictMixin:
|
||||
# Mixin defining all dictionary methods for classes that already have
|
||||
# a minimum dictionary interface including getitem, setitem, delitem,
|
||||
# and keys. Without knowledge of the subclass constructor, the mixin
|
||||
# does not define __init__() or copy(). In addition to the four base
|
||||
# methods, progressively more efficiency comes with defining
|
||||
# __contains__(), __iter__(), and iteritems().
|
||||
|
||||
# second level definitions support higher levels
|
||||
def __iter__(self):
|
||||
for k in self.keys():
|
||||
yield k
|
||||
def has_key(self, key):
|
||||
try:
|
||||
value = self[key]
|
||||
except KeyError:
|
||||
return False
|
||||
return True
|
||||
def __contains__(self, key):
|
||||
return self.has_key(key)
|
||||
|
||||
# third level takes advantage of second level definitions
|
||||
def iteritems(self):
|
||||
for k in self:
|
||||
yield (k, self[k])
|
||||
def iterkeys(self):
|
||||
return self.__iter__()
|
||||
|
||||
# fourth level uses definitions from lower levels
|
||||
def itervalues(self):
|
||||
for _, v in self.iteritems():
|
||||
yield v
|
||||
def values(self):
|
||||
return [v for _, v in self.iteritems()]
|
||||
def items(self):
|
||||
return list(self.iteritems())
|
||||
def clear(self):
|
||||
for key in self.keys():
|
||||
del self[key]
|
||||
def setdefault(self, key, default):
|
||||
try:
|
||||
return self[key]
|
||||
except KeyError:
|
||||
self[key] = default
|
||||
return default
|
||||
def pop(self, key, *args):
|
||||
if len(args) > 1:
|
||||
raise TypeError, "pop expected at most 2 arguments, got "\
|
||||
+ repr(1 + len(args))
|
||||
try:
|
||||
value = self[key]
|
||||
except KeyError:
|
||||
if args:
|
||||
return args[0]
|
||||
raise
|
||||
del self[key]
|
||||
return value
|
||||
def popitem(self):
|
||||
try:
|
||||
k, v = self.iteritems().next()
|
||||
except StopIteration:
|
||||
raise KeyError, 'container is empty'
|
||||
del self[k]
|
||||
return (k, v)
|
||||
def update(self, other):
|
||||
# Make progressively weaker assumptions about "other"
|
||||
if hasattr(other, 'iteritems'): # iteritems saves memory and lookups
|
||||
for k, v in other.iteritems():
|
||||
self[k] = v
|
||||
elif hasattr(other, '__iter__'): # iter saves memory
|
||||
for k in other:
|
||||
self[k] = other[k]
|
||||
else:
|
||||
for k in other.keys():
|
||||
self[k] = other[k]
|
||||
def get(self, key, default=None):
|
||||
try:
|
||||
return self[key]
|
||||
except KeyError:
|
||||
return default
|
||||
def __repr__(self):
|
||||
return repr(dict(self.iteritems()))
|
||||
def __cmp__(self, other):
|
||||
if other is None:
|
||||
return 1
|
||||
if isinstance(other, DictMixin):
|
||||
other = dict(other.iteritems())
|
||||
return cmp(dict(self.iteritems()), other)
|
||||
def __len__(self):
|
||||
return len(self.keys())
|
||||
|
||||
###########################################################################
|
||||
|
||||
from _psyco import compact
|
||||
|
||||
|
||||
class compactdictproxy(DictMixin):
|
||||
|
||||
def __init__(self, ko):
|
||||
self._ko = ko # compact object of which 'self' is the dict
|
||||
|
||||
def __getitem__(self, key):
|
||||
return compact.__getslot__(self._ko, key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
compact.__setslot__(self._ko, key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
compact.__delslot__(self._ko, key)
|
||||
|
||||
def keys(self):
|
||||
return compact.__members__.__get__(self._ko)
|
||||
|
||||
def clear(self):
|
||||
keys = self.keys()
|
||||
keys.reverse()
|
||||
for key in keys:
|
||||
del self[key]
|
||||
|
||||
def __repr__(self):
|
||||
keys = ', '.join(self.keys())
|
||||
return '<compactdictproxy object {%s}>' % (keys,)
|
||||
@@ -1,96 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco logger.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco logger.
|
||||
|
||||
See log() in core.py.
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
|
||||
import _psyco
|
||||
from time import time, localtime, strftime
|
||||
|
||||
|
||||
current = None
|
||||
print_charges = 10
|
||||
dump_delay = 0.2
|
||||
dump_last = 0.0
|
||||
|
||||
def write(s, level):
|
||||
t = time()
|
||||
f = t-int(t)
|
||||
try:
|
||||
current.write("%s.%02d %-*s%s\n" % (
|
||||
strftime("%X", localtime(int(t))),
|
||||
int(f*100.0), 63-level, s,
|
||||
"%"*level))
|
||||
current.flush()
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
def psycowrite(s):
|
||||
t = time()
|
||||
f = t-int(t)
|
||||
try:
|
||||
current.write("%s.%02d %-*s%s\n" % (
|
||||
strftime("%X", localtime(int(t))),
|
||||
int(f*100.0), 60, s.strip(),
|
||||
"% %"))
|
||||
current.flush()
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
##def writelines(lines, level=0):
|
||||
## if lines:
|
||||
## t = time()
|
||||
## f = t-int(t)
|
||||
## timedesc = strftime("%x %X", localtime(int(t)))
|
||||
## print >> current, "%s.%03d %-*s %s" % (
|
||||
## timedesc, int(f*1000),
|
||||
## 50-level, lines[0],
|
||||
## "+"*level)
|
||||
## timedesc = " " * (len(timedesc)+5)
|
||||
## for line in lines[1:]:
|
||||
## print >> current, timedesc, line
|
||||
|
||||
def writememory():
|
||||
write("memory usage: %d+ kb" % _psyco.memory(), 1)
|
||||
|
||||
def dumpcharges():
|
||||
global dump_last
|
||||
if print_charges:
|
||||
t = time()
|
||||
if not (dump_last <= t < dump_last+dump_delay):
|
||||
if t <= dump_last+1.5*dump_delay:
|
||||
dump_last += dump_delay
|
||||
else:
|
||||
dump_last = t
|
||||
#write("%s: charges:" % who, 0)
|
||||
lst = _psyco.stattop(print_charges)
|
||||
if lst:
|
||||
f = t-int(t)
|
||||
lines = ["%s.%02d ______\n" % (
|
||||
strftime("%X", localtime(int(t))),
|
||||
int(f*100.0))]
|
||||
i = 1
|
||||
for co, charge in lst:
|
||||
detail = co.co_filename
|
||||
if len(detail) > 19:
|
||||
detail = '...' + detail[-17:]
|
||||
lines.append(" #%-3d |%4.1f %%| %-26s%20s:%d\n" %
|
||||
(i, charge*100.0, co.co_name, detail,
|
||||
co.co_firstlineno))
|
||||
i += 1
|
||||
current.writelines(lines)
|
||||
current.flush()
|
||||
|
||||
def writefinalstats():
|
||||
dumpcharges()
|
||||
writememory()
|
||||
writedate("program exit")
|
||||
|
||||
def writedate(msg):
|
||||
write('%s, %s' % (msg, strftime("%x")), 20)
|
||||
@@ -1,379 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco profiler (Python part).
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco profiler (Python part).
|
||||
|
||||
The implementation of the non-time-critical parts of the profiler.
|
||||
See profile() and full() in core.py for the easy interface.
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
import _psyco
|
||||
from support import *
|
||||
import math, time, types, atexit
|
||||
now = time.time
|
||||
try:
|
||||
import thread
|
||||
except ImportError:
|
||||
import dummy_thread as thread
|
||||
|
||||
|
||||
# current profiler instance
|
||||
current = None
|
||||
|
||||
# enabled profilers, in order of priority
|
||||
profilers = []
|
||||
|
||||
# logger module (when enabled by core.log())
|
||||
logger = None
|
||||
|
||||
# a lock for a thread-safe go()
|
||||
go_lock = thread.allocate_lock()
|
||||
|
||||
def go(stop=0):
|
||||
# run the highest-priority profiler in 'profilers'
|
||||
global current
|
||||
go_lock.acquire()
|
||||
try:
|
||||
prev = current
|
||||
if stop:
|
||||
del profilers[:]
|
||||
if prev:
|
||||
if profilers and profilers[0] is prev:
|
||||
return # best profiler already running
|
||||
prev.stop()
|
||||
current = None
|
||||
for p in profilers[:]:
|
||||
if p.start():
|
||||
current = p
|
||||
if logger: # and p is not prev:
|
||||
logger.write("%s: starting" % p.__class__.__name__, 5)
|
||||
return
|
||||
finally:
|
||||
go_lock.release()
|
||||
# no profiler is running now
|
||||
if stop:
|
||||
if logger:
|
||||
logger.writefinalstats()
|
||||
else:
|
||||
tag2bind()
|
||||
|
||||
atexit.register(go, 1)
|
||||
|
||||
|
||||
def buildfncache(globals, cache):
|
||||
if hasattr(types.IntType, '__dict__'):
|
||||
clstypes = (types.ClassType, types.TypeType)
|
||||
else:
|
||||
clstypes = types.ClassType
|
||||
for x in globals.values():
|
||||
if isinstance(x, types.MethodType):
|
||||
x = x.im_func
|
||||
if isinstance(x, types.FunctionType):
|
||||
cache[x.func_code] = x, ''
|
||||
elif isinstance(x, clstypes):
|
||||
for y in x.__dict__.values():
|
||||
if isinstance(y, types.MethodType):
|
||||
y = y.im_func
|
||||
if isinstance(y, types.FunctionType):
|
||||
cache[y.func_code] = y, x.__name__
|
||||
|
||||
# code-to-function mapping (cache)
|
||||
function_cache = {}
|
||||
|
||||
def trytobind(co, globals, log=1):
|
||||
try:
|
||||
f, clsname = function_cache[co]
|
||||
except KeyError:
|
||||
buildfncache(globals, function_cache)
|
||||
try:
|
||||
f, clsname = function_cache[co]
|
||||
except KeyError:
|
||||
if logger:
|
||||
logger.write('warning: cannot find function %s in %s' %
|
||||
(co.co_name, globals.get('__name__', '?')), 3)
|
||||
return # give up
|
||||
if logger and log:
|
||||
modulename = globals.get('__name__', '?')
|
||||
if clsname:
|
||||
modulename += '.' + clsname
|
||||
logger.write('bind function: %s.%s' % (modulename, co.co_name), 1)
|
||||
f.func_code = _psyco.proxycode(f)
|
||||
|
||||
|
||||
# the list of code objects that have been tagged
|
||||
tagged_codes = []
|
||||
|
||||
def tag(co, globals):
|
||||
if logger:
|
||||
try:
|
||||
f, clsname = function_cache[co]
|
||||
except KeyError:
|
||||
buildfncache(globals, function_cache)
|
||||
try:
|
||||
f, clsname = function_cache[co]
|
||||
except KeyError:
|
||||
clsname = '' # give up
|
||||
modulename = globals.get('__name__', '?')
|
||||
if clsname:
|
||||
modulename += '.' + clsname
|
||||
logger.write('tag function: %s.%s' % (modulename, co.co_name), 1)
|
||||
tagged_codes.append((co, globals))
|
||||
_psyco.turbo_frame(co)
|
||||
_psyco.turbo_code(co)
|
||||
|
||||
def tag2bind():
|
||||
if tagged_codes:
|
||||
if logger:
|
||||
logger.write('profiling stopped, binding %d functions' %
|
||||
len(tagged_codes), 2)
|
||||
for co, globals in tagged_codes:
|
||||
trytobind(co, globals, 0)
|
||||
function_cache.clear()
|
||||
del tagged_codes[:]
|
||||
|
||||
|
||||
class Profiler:
|
||||
MemoryTimerResolution = 0.103
|
||||
|
||||
def run(self, memory, time, memorymax, timemax):
|
||||
self.memory = memory
|
||||
self.memorymax = memorymax
|
||||
self.time = time
|
||||
if timemax is None:
|
||||
self.endtime = None
|
||||
else:
|
||||
self.endtime = now() + timemax
|
||||
self.alarms = []
|
||||
profilers.append(self)
|
||||
go()
|
||||
|
||||
def start(self):
|
||||
curmem = _psyco.memory()
|
||||
memlimits = []
|
||||
if self.memorymax is not None:
|
||||
if curmem >= self.memorymax:
|
||||
if logger:
|
||||
logger.writememory()
|
||||
return self.limitreached('memorymax')
|
||||
memlimits.append(self.memorymax)
|
||||
if self.memory is not None:
|
||||
if self.memory <= 0:
|
||||
if logger:
|
||||
logger.writememory()
|
||||
return self.limitreached('memory')
|
||||
memlimits.append(curmem + self.memory)
|
||||
self.memory_at_start = curmem
|
||||
|
||||
curtime = now()
|
||||
timelimits = []
|
||||
if self.endtime is not None:
|
||||
if curtime >= self.endtime:
|
||||
return self.limitreached('timemax')
|
||||
timelimits.append(self.endtime - curtime)
|
||||
if self.time is not None:
|
||||
if self.time <= 0.0:
|
||||
return self.limitreached('time')
|
||||
timelimits.append(self.time)
|
||||
self.time_at_start = curtime
|
||||
|
||||
try:
|
||||
self.do_start()
|
||||
except error, e:
|
||||
if logger:
|
||||
logger.write('%s: disabled by psyco.error:' % (
|
||||
self.__class__.__name__), 4)
|
||||
logger.write(' %s' % str(e), 3)
|
||||
return 0
|
||||
|
||||
if memlimits:
|
||||
self.memlimits_args = (time.sleep, (self.MemoryTimerResolution,),
|
||||
self.check_memory, (min(memlimits),))
|
||||
self.alarms.append(_psyco.alarm(*self.memlimits_args))
|
||||
if timelimits:
|
||||
self.alarms.append(_psyco.alarm(time.sleep, (min(timelimits),),
|
||||
self.time_out))
|
||||
return 1
|
||||
|
||||
def stop(self):
|
||||
for alarm in self.alarms:
|
||||
alarm.stop(0)
|
||||
for alarm in self.alarms:
|
||||
alarm.stop(1) # wait for parallel threads to stop
|
||||
del self.alarms[:]
|
||||
if self.time is not None:
|
||||
self.time -= now() - self.time_at_start
|
||||
if self.memory is not None:
|
||||
self.memory -= _psyco.memory() - self.memory_at_start
|
||||
|
||||
try:
|
||||
self.do_stop()
|
||||
except error:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def check_memory(self, limit):
|
||||
if _psyco.memory() < limit:
|
||||
return self.memlimits_args
|
||||
go()
|
||||
|
||||
def time_out(self):
|
||||
self.time = 0.0
|
||||
go()
|
||||
|
||||
def limitreached(self, limitname):
|
||||
try:
|
||||
profilers.remove(self)
|
||||
except ValueError:
|
||||
pass
|
||||
if logger:
|
||||
logger.write('%s: disabled (%s limit reached)' % (
|
||||
self.__class__.__name__, limitname), 4)
|
||||
return 0
|
||||
|
||||
|
||||
class FullCompiler(Profiler):
|
||||
|
||||
def do_start(self):
|
||||
_psyco.profiling('f')
|
||||
|
||||
def do_stop(self):
|
||||
_psyco.profiling('.')
|
||||
|
||||
|
||||
class RunOnly(Profiler):
|
||||
|
||||
def do_start(self):
|
||||
_psyco.profiling('n')
|
||||
|
||||
def do_stop(self):
|
||||
_psyco.profiling('.')
|
||||
|
||||
|
||||
class ChargeProfiler(Profiler):
|
||||
|
||||
def __init__(self, watermark, parentframe):
|
||||
self.watermark = watermark
|
||||
self.parent2 = parentframe * 2.0
|
||||
self.lock = thread.allocate_lock()
|
||||
|
||||
def init_charges(self):
|
||||
_psyco.statwrite(watermark = self.watermark,
|
||||
parent2 = self.parent2)
|
||||
|
||||
def do_stop(self):
|
||||
_psyco.profiling('.')
|
||||
_psyco.statwrite(callback = None)
|
||||
|
||||
|
||||
class ActiveProfiler(ChargeProfiler):
|
||||
|
||||
def active_start(self):
|
||||
_psyco.profiling('p')
|
||||
|
||||
def do_start(self):
|
||||
self.init_charges()
|
||||
self.active_start()
|
||||
_psyco.statwrite(callback = self.charge_callback)
|
||||
|
||||
def charge_callback(self, frame, charge):
|
||||
tag(frame.f_code, frame.f_globals)
|
||||
|
||||
|
||||
class PassiveProfiler(ChargeProfiler):
|
||||
|
||||
initial_charge_unit = _psyco.statread('unit')
|
||||
reset_stats_after = 120 # half-lives (maximum 200!)
|
||||
reset_limit = initial_charge_unit * (2.0 ** reset_stats_after)
|
||||
|
||||
def __init__(self, watermark, halflife, pollfreq, parentframe):
|
||||
ChargeProfiler.__init__(self, watermark, parentframe)
|
||||
self.pollfreq = pollfreq
|
||||
# self.progress is slightly more than 1.0, and computed so that
|
||||
# do_profile() will double the change_unit every 'halflife' seconds.
|
||||
self.progress = 2.0 ** (1.0 / (halflife * pollfreq))
|
||||
|
||||
def reset(self):
|
||||
_psyco.statwrite(unit = self.initial_charge_unit, callback = None)
|
||||
_psyco.statreset()
|
||||
if logger:
|
||||
logger.write("%s: resetting stats" % self.__class__.__name__, 1)
|
||||
|
||||
def passive_start(self):
|
||||
self.passivealarm_args = (time.sleep, (1.0 / self.pollfreq,),
|
||||
self.do_profile)
|
||||
self.alarms.append(_psyco.alarm(*self.passivealarm_args))
|
||||
|
||||
def do_start(self):
|
||||
tag2bind()
|
||||
self.init_charges()
|
||||
self.passive_start()
|
||||
|
||||
def do_profile(self):
|
||||
_psyco.statcollect()
|
||||
if logger:
|
||||
logger.dumpcharges()
|
||||
nunit = _psyco.statread('unit') * self.progress
|
||||
if nunit > self.reset_limit:
|
||||
self.reset()
|
||||
else:
|
||||
_psyco.statwrite(unit = nunit, callback = self.charge_callback)
|
||||
return self.passivealarm_args
|
||||
|
||||
def charge_callback(self, frame, charge):
|
||||
trytobind(frame.f_code, frame.f_globals)
|
||||
|
||||
|
||||
class ActivePassiveProfiler(PassiveProfiler, ActiveProfiler):
|
||||
|
||||
def do_start(self):
|
||||
self.init_charges()
|
||||
self.active_start()
|
||||
self.passive_start()
|
||||
|
||||
def charge_callback(self, frame, charge):
|
||||
tag(frame.f_code, frame.f_globals)
|
||||
|
||||
|
||||
|
||||
#
|
||||
# we register our own version of sys.settrace(), sys.setprofile()
|
||||
# and thread.start_new_thread().
|
||||
#
|
||||
|
||||
def psyco_settrace(*args, **kw):
|
||||
"This is the Psyco-aware version of sys.settrace()."
|
||||
result = original_settrace(*args, **kw)
|
||||
go()
|
||||
return result
|
||||
|
||||
def psyco_setprofile(*args, **kw):
|
||||
"This is the Psyco-aware version of sys.setprofile()."
|
||||
result = original_setprofile(*args, **kw)
|
||||
go()
|
||||
return result
|
||||
|
||||
def psyco_thread_stub(callable, args, kw):
|
||||
_psyco.statcollect()
|
||||
if kw is None:
|
||||
return callable(*args)
|
||||
else:
|
||||
return callable(*args, **kw)
|
||||
|
||||
def psyco_start_new_thread(callable, args, kw=None):
|
||||
"This is the Psyco-aware version of thread.start_new_thread()."
|
||||
return original_start_new_thread(psyco_thread_stub, (callable, args, kw))
|
||||
|
||||
original_settrace = sys.settrace
|
||||
original_setprofile = sys.setprofile
|
||||
original_start_new_thread = thread.start_new_thread
|
||||
sys.settrace = psyco_settrace
|
||||
sys.setprofile = psyco_setprofile
|
||||
thread.start_new_thread = psyco_start_new_thread
|
||||
# hack to patch threading._start_new_thread if the module is
|
||||
# already loaded
|
||||
if ('threading' in sys.modules and
|
||||
hasattr(sys.modules['threading'], '_start_new_thread')):
|
||||
sys.modules['threading']._start_new_thread = psyco_start_new_thread
|
||||
@@ -1,191 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# Psyco general support module.
|
||||
# Copyright (C) 2001-2002 Armin Rigo et.al.
|
||||
|
||||
"""Psyco general support module.
|
||||
|
||||
For internal use.
|
||||
"""
|
||||
###########################################################################
|
||||
|
||||
import sys, _psyco, __builtin__
|
||||
|
||||
error = _psyco.error
|
||||
class warning(Warning):
|
||||
pass
|
||||
|
||||
_psyco.NoLocalsWarning = warning
|
||||
|
||||
def warn(msg):
|
||||
from warnings import warn
|
||||
warn(msg, warning, stacklevel=2)
|
||||
|
||||
#
|
||||
# Version checks
|
||||
#
|
||||
__version__ = 0x010600f0
|
||||
if _psyco.PSYVER != __version__:
|
||||
raise error, "version mismatch between Psyco parts, reinstall it"
|
||||
|
||||
version_info = (__version__ >> 24,
|
||||
(__version__ >> 16) & 0xff,
|
||||
(__version__ >> 8) & 0xff,
|
||||
{0xa0: 'alpha',
|
||||
0xb0: 'beta',
|
||||
0xc0: 'candidate',
|
||||
0xf0: 'final'}[__version__ & 0xf0],
|
||||
__version__ & 0xf)
|
||||
|
||||
|
||||
VERSION_LIMITS = [0x02020200, # 2.2.2
|
||||
0x02030000, # 2.3
|
||||
0x02040000] # 2.4
|
||||
|
||||
if ([v for v in VERSION_LIMITS if v <= sys.hexversion] !=
|
||||
[v for v in VERSION_LIMITS if v <= _psyco.PYVER ]):
|
||||
if sys.hexversion < VERSION_LIMITS[0]:
|
||||
warn("Psyco requires Python version 2.2.2 or later")
|
||||
else:
|
||||
warn("Psyco version does not match Python version. "
|
||||
"Psyco must be updated or recompiled")
|
||||
|
||||
|
||||
if hasattr(_psyco, 'ALL_CHECKS') and hasattr(_psyco, 'VERBOSE_LEVEL'):
|
||||
print >> sys.stderr, ('psyco: running in debugging mode on %s' %
|
||||
_psyco.PROCESSOR)
|
||||
|
||||
|
||||
###########################################################################
|
||||
# sys._getframe() gives strange results on a mixed Psyco- and Python-style
|
||||
# stack frame. Psyco provides a replacement that partially emulates Python
|
||||
# frames from Psyco frames. The new sys._getframe() may return objects of
|
||||
# a custom "Psyco frame" type, which is a subtype of the normal frame type.
|
||||
#
|
||||
# The same problems require some other built-in functions to be replaced
|
||||
# as well. Note that the local variables are not available in any
|
||||
# dictionary with Psyco.
|
||||
|
||||
|
||||
class Frame:
|
||||
pass
|
||||
|
||||
|
||||
class PythonFrame(Frame):
|
||||
|
||||
def __init__(self, frame):
|
||||
self.__dict__.update({
|
||||
'_frame': frame,
|
||||
})
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'f_back':
|
||||
try:
|
||||
result = embedframe(_psyco.getframe(self._frame))
|
||||
except ValueError:
|
||||
result = None
|
||||
except error:
|
||||
warn("f_back is skipping dead Psyco frames")
|
||||
result = self._frame.f_back
|
||||
self.__dict__['f_back'] = result
|
||||
return result
|
||||
else:
|
||||
return getattr(self._frame, attr)
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
setattr(self._frame, attr, value)
|
||||
|
||||
def __delattr__(self, attr):
|
||||
delattr(self._frame, attr)
|
||||
|
||||
|
||||
class PsycoFrame(Frame):
|
||||
|
||||
def __init__(self, tag):
|
||||
self.__dict__.update({
|
||||
'_tag' : tag,
|
||||
'f_code' : tag[0],
|
||||
'f_globals': tag[1],
|
||||
})
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr == 'f_back':
|
||||
try:
|
||||
result = embedframe(_psyco.getframe(self._tag))
|
||||
except ValueError:
|
||||
result = None
|
||||
elif attr == 'f_lineno':
|
||||
result = self.f_code.co_firstlineno # better than nothing
|
||||
elif attr == 'f_builtins':
|
||||
result = self.f_globals['__builtins__']
|
||||
elif attr == 'f_restricted':
|
||||
result = self.f_builtins is not __builtins__
|
||||
elif attr == 'f_locals':
|
||||
raise AttributeError, ("local variables of functions run by Psyco "
|
||||
"cannot be accessed in any way, sorry")
|
||||
else:
|
||||
raise AttributeError, ("emulated Psyco frames have "
|
||||
"no '%s' attribute" % attr)
|
||||
self.__dict__[attr] = result
|
||||
return result
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
raise AttributeError, "Psyco frame objects are read-only"
|
||||
|
||||
def __delattr__(self, attr):
|
||||
if attr == 'f_trace':
|
||||
# for bdb which relies on CPython frames exhibiting a slightly
|
||||
# buggy behavior: you can 'del f.f_trace' as often as you like
|
||||
# even without having set it previously.
|
||||
return
|
||||
raise AttributeError, "Psyco frame objects are read-only"
|
||||
|
||||
|
||||
def embedframe(result):
|
||||
if type(result) is type(()):
|
||||
return PsycoFrame(result)
|
||||
else:
|
||||
return PythonFrame(result)
|
||||
|
||||
def _getframe(depth=0):
|
||||
"""Return a frame object from the call stack. This is a replacement for
|
||||
sys._getframe() which is aware of Psyco frames.
|
||||
|
||||
The returned objects are instances of either PythonFrame or PsycoFrame
|
||||
instead of being real Python-level frame object, so that they can emulate
|
||||
the common attributes of frame objects.
|
||||
|
||||
The original sys._getframe() ignoring Psyco frames altogether is stored in
|
||||
psyco._getrealframe(). See also psyco._getemulframe()."""
|
||||
# 'depth+1' to account for this _getframe() Python function
|
||||
return embedframe(_psyco.getframe(depth+1))
|
||||
|
||||
def _getemulframe(depth=0):
|
||||
"""As _getframe(), but the returned objects are real Python frame objects
|
||||
emulating Psyco frames. Some of their attributes can be wrong or missing,
|
||||
however."""
|
||||
# 'depth+1' to account for this _getemulframe() Python function
|
||||
return _psyco.getframe(depth+1, 1)
|
||||
|
||||
def patch(name, module=__builtin__):
|
||||
f = getattr(_psyco, name)
|
||||
org = getattr(module, name)
|
||||
if org is not f:
|
||||
setattr(module, name, f)
|
||||
setattr(_psyco, 'original_' + name, org)
|
||||
|
||||
_getrealframe = sys._getframe
|
||||
sys._getframe = _getframe
|
||||
patch('globals')
|
||||
patch('eval')
|
||||
patch('execfile')
|
||||
patch('locals')
|
||||
patch('vars')
|
||||
patch('dir')
|
||||
patch('input')
|
||||
_psyco.original_raw_input = raw_input
|
||||
__builtin__.__in_psyco__ = 0==1 # False
|
||||
|
||||
if hasattr(_psyco, 'compact'):
|
||||
import kdictproxy
|
||||
_psyco.compactdictproxy = kdictproxy.compactdictproxy
|
||||
218
Calibre_Plugins/eReaderPDB2PML_plugin/python_des.py
Normal file
218
Calibre_Plugins/eReaderPDB2PML_plugin/python_des.py
Normal file
@@ -0,0 +1,218 @@
|
||||
import sys
|
||||
|
||||
ECB = 0
|
||||
CBC = 1
|
||||
class Des(object):
|
||||
__pc1 = [56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
|
||||
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
|
||||
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
|
||||
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3]
|
||||
__left_rotations = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]
|
||||
__pc2 = [13, 16, 10, 23, 0, 4,2, 27, 14, 5, 20, 9,
|
||||
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
|
||||
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
|
||||
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31]
|
||||
__ip = [57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
|
||||
61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7,
|
||||
56, 48, 40, 32, 24, 16, 8, 0, 58, 50, 42, 34, 26, 18, 10, 2,
|
||||
60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6]
|
||||
__expansion_table = [31, 0, 1, 2, 3, 4, 3, 4, 5, 6, 7, 8,
|
||||
7, 8, 9, 10, 11, 12,11, 12, 13, 14, 15, 16,
|
||||
15, 16, 17, 18, 19, 20,19, 20, 21, 22, 23, 24,
|
||||
23, 24, 25, 26, 27, 28,27, 28, 29, 30, 31, 0]
|
||||
__sbox = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
|
||||
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
|
||||
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
|
||||
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13],
|
||||
[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
|
||||
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
|
||||
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
|
||||
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9],
|
||||
[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
|
||||
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
|
||||
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
|
||||
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12],
|
||||
[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
|
||||
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
|
||||
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
|
||||
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14],
|
||||
[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
|
||||
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
|
||||
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
|
||||
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3],
|
||||
[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
|
||||
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
|
||||
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
|
||||
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13],
|
||||
[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
|
||||
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
|
||||
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
|
||||
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12],
|
||||
[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
|
||||
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
|
||||
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
|
||||
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11],]
|
||||
__p = [15, 6, 19, 20, 28, 11,27, 16, 0, 14, 22, 25,
|
||||
4, 17, 30, 9, 1, 7,23,13, 31, 26, 2, 8,18, 12, 29, 5, 21, 10,3, 24]
|
||||
__fp = [39, 7, 47, 15, 55, 23, 63, 31,38, 6, 46, 14, 54, 22, 62, 30,
|
||||
37, 5, 45, 13, 53, 21, 61, 29,36, 4, 44, 12, 52, 20, 60, 28,
|
||||
35, 3, 43, 11, 51, 19, 59, 27,34, 2, 42, 10, 50, 18, 58, 26,
|
||||
33, 1, 41, 9, 49, 17, 57, 25,32, 0, 40, 8, 48, 16, 56, 24]
|
||||
# Type of crypting being done
|
||||
ENCRYPT = 0x00
|
||||
DECRYPT = 0x01
|
||||
def __init__(self, key, mode=ECB, IV=None):
|
||||
if len(key) != 8:
|
||||
raise ValueError("Invalid DES key size. Key must be exactly 8 bytes long.")
|
||||
self.block_size = 8
|
||||
self.key_size = 8
|
||||
self.__padding = ''
|
||||
self.setMode(mode)
|
||||
if IV:
|
||||
self.setIV(IV)
|
||||
self.L = []
|
||||
self.R = []
|
||||
self.Kn = [ [0] * 48 ] * 16 # 16 48-bit keys (K1 - K16)
|
||||
self.final = []
|
||||
self.setKey(key)
|
||||
def getKey(self):
|
||||
return self.__key
|
||||
def setKey(self, key):
|
||||
self.__key = key
|
||||
self.__create_sub_keys()
|
||||
def getMode(self):
|
||||
return self.__mode
|
||||
def setMode(self, mode):
|
||||
self.__mode = mode
|
||||
def getIV(self):
|
||||
return self.__iv
|
||||
def setIV(self, IV):
|
||||
if not IV or len(IV) != self.block_size:
|
||||
raise ValueError("Invalid Initial Value (IV), must be a multiple of " + str(self.block_size) + " bytes")
|
||||
self.__iv = IV
|
||||
def getPadding(self):
|
||||
return self.__padding
|
||||
def __String_to_BitList(self, data):
|
||||
l = len(data) * 8
|
||||
result = [0] * l
|
||||
pos = 0
|
||||
for c in data:
|
||||
i = 7
|
||||
ch = ord(c)
|
||||
while i >= 0:
|
||||
if ch & (1 << i) != 0:
|
||||
result[pos] = 1
|
||||
else:
|
||||
result[pos] = 0
|
||||
pos += 1
|
||||
i -= 1
|
||||
return result
|
||||
def __BitList_to_String(self, data):
|
||||
result = ''
|
||||
pos = 0
|
||||
c = 0
|
||||
while pos < len(data):
|
||||
c += data[pos] << (7 - (pos % 8))
|
||||
if (pos % 8) == 7:
|
||||
result += chr(c)
|
||||
c = 0
|
||||
pos += 1
|
||||
return result
|
||||
def __permutate(self, table, block):
|
||||
return [block[x] for x in table]
|
||||
def __create_sub_keys(self):
|
||||
key = self.__permutate(Des.__pc1, self.__String_to_BitList(self.getKey()))
|
||||
i = 0
|
||||
self.L = key[:28]
|
||||
self.R = key[28:]
|
||||
while i < 16:
|
||||
j = 0
|
||||
while j < Des.__left_rotations[i]:
|
||||
self.L.append(self.L[0])
|
||||
del self.L[0]
|
||||
self.R.append(self.R[0])
|
||||
del self.R[0]
|
||||
j += 1
|
||||
self.Kn[i] = self.__permutate(Des.__pc2, self.L + self.R)
|
||||
i += 1
|
||||
def __des_crypt(self, block, crypt_type):
|
||||
block = self.__permutate(Des.__ip, block)
|
||||
self.L = block[:32]
|
||||
self.R = block[32:]
|
||||
if crypt_type == Des.ENCRYPT:
|
||||
iteration = 0
|
||||
iteration_adjustment = 1
|
||||
else:
|
||||
iteration = 15
|
||||
iteration_adjustment = -1
|
||||
i = 0
|
||||
while i < 16:
|
||||
tempR = self.R[:]
|
||||
self.R = self.__permutate(Des.__expansion_table, self.R)
|
||||
self.R = [x ^ y for x,y in zip(self.R, self.Kn[iteration])]
|
||||
B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]]
|
||||
j = 0
|
||||
Bn = [0] * 32
|
||||
pos = 0
|
||||
while j < 8:
|
||||
m = (B[j][0] << 1) + B[j][5]
|
||||
n = (B[j][1] << 3) + (B[j][2] << 2) + (B[j][3] << 1) + B[j][4]
|
||||
v = Des.__sbox[j][(m << 4) + n]
|
||||
Bn[pos] = (v & 8) >> 3
|
||||
Bn[pos + 1] = (v & 4) >> 2
|
||||
Bn[pos + 2] = (v & 2) >> 1
|
||||
Bn[pos + 3] = v & 1
|
||||
pos += 4
|
||||
j += 1
|
||||
self.R = self.__permutate(Des.__p, Bn)
|
||||
self.R = [x ^ y for x, y in zip(self.R, self.L)]
|
||||
self.L = tempR
|
||||
i += 1
|
||||
iteration += iteration_adjustment
|
||||
self.final = self.__permutate(Des.__fp, self.R + self.L)
|
||||
return self.final
|
||||
def crypt(self, data, crypt_type):
|
||||
if not data:
|
||||
return ''
|
||||
if len(data) % self.block_size != 0:
|
||||
if crypt_type == Des.DECRYPT: # Decryption must work on 8 byte blocks
|
||||
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n.")
|
||||
if not self.getPadding():
|
||||
raise ValueError("Invalid data length, data must be a multiple of " + str(self.block_size) + " bytes\n. Try setting the optional padding character")
|
||||
else:
|
||||
data += (self.block_size - (len(data) % self.block_size)) * self.getPadding()
|
||||
if self.getMode() == CBC:
|
||||
if self.getIV():
|
||||
iv = self.__String_to_BitList(self.getIV())
|
||||
else:
|
||||
raise ValueError("For CBC mode, you must supply the Initial Value (IV) for ciphering")
|
||||
i = 0
|
||||
dict = {}
|
||||
result = []
|
||||
while i < len(data):
|
||||
block = self.__String_to_BitList(data[i:i+8])
|
||||
if self.getMode() == CBC:
|
||||
if crypt_type == Des.ENCRYPT:
|
||||
block = [x ^ y for x, y in zip(block, iv)]
|
||||
processed_block = self.__des_crypt(block, crypt_type)
|
||||
if crypt_type == Des.DECRYPT:
|
||||
processed_block = [x ^ y for x, y in zip(processed_block, iv)]
|
||||
iv = block
|
||||
else:
|
||||
iv = processed_block
|
||||
else:
|
||||
processed_block = self.__des_crypt(block, crypt_type)
|
||||
result.append(self.__BitList_to_String(processed_block))
|
||||
i += 8
|
||||
if crypt_type == Des.DECRYPT and self.getPadding():
|
||||
s = result[-1]
|
||||
while s[-1] == self.getPadding():
|
||||
s = s[:-1]
|
||||
result[-1] = s
|
||||
return ''.join(result)
|
||||
def encrypt(self, data, pad=''):
|
||||
self.__padding = pad
|
||||
return self.crypt(data, Des.ENCRYPT)
|
||||
def decrypt(self, data, pad=''):
|
||||
self.__padding = pad
|
||||
return self.crypt(data, Des.DECRYPT)
|
||||
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/__init__.pyo
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/__init__.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/_psyco.pyd
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/_psyco.pyd
Normal file
Binary file not shown.
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/builtin.pyo
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/builtin.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/classes.pyo
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/classes.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/clibrary.pyo
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/clibrary.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/core.pyo
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/core.pyo
Normal file
Binary file not shown.
Binary file not shown.
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/logger.pyo
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/logger.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/profiler.pyo
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/profiler.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/support.pyo
Normal file
BIN
Calibre_Plugins/eReaderPDB2PML_plugin/windows/psyco/support.pyo
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,65 +0,0 @@
|
||||
Ignoble Epub DeDRM - ignobleepub_vXX_plugin.zip
|
||||
Requires Calibre version 0.6.44 or higher.
|
||||
|
||||
All credit given to I <3 Cabbages for the original standalone scripts.
|
||||
I had the much easier job of converting them to a Calibre plugin.
|
||||
|
||||
This plugin is meant to decrypt Barnes & Noble Epubs that are protected
|
||||
with Adobe's Adept encryption. It is meant to function without having to install
|
||||
any dependencies... other than having Calibre installed, of course. It will still
|
||||
work if you have Python and PyCrypto already installed, but they aren't necessary.
|
||||
|
||||
Installation:
|
||||
|
||||
Go to Calibre's Preferences page... click on the Plugins button. Use the file
|
||||
dialog button to select the plugin's zip file (ignobleepub_vXX_plugin.zip) and
|
||||
click the 'Add' button. you're done.
|
||||
|
||||
Configuration:
|
||||
|
||||
1) The easiest way to configure the plugin is to enter your name (Barnes & Noble account
|
||||
name) and credit card number (the one used to purchase the books) into the plugin's
|
||||
customization window. It's the same info you would enter into the ignoblekeygen script.
|
||||
Highlight the plugin (Ignoble Epub DeDRM) and click the "Customize Plugin" button on
|
||||
Calibre's Preferences->Plugins page. Enter the name and credit card number separated
|
||||
by a comma: Your Name,1234123412341234
|
||||
|
||||
If you've purchased books with more than one credit card, separate that other info with
|
||||
a colon: Your Name,1234123412341234:Other Name,2345234523452345
|
||||
|
||||
** NOTE ** The above method is your only option if you don't have/can't run the original
|
||||
I <3 Cabbages scripts on your particular machine.
|
||||
|
||||
** NOTE ** Your credit card number will be on display in Calibre's Plugin configuration
|
||||
page when using the above method. If other people have access to your computer,
|
||||
you may want to use the second configuration method below.
|
||||
|
||||
2) If you already have keyfiles generated with I <3 Cabbages' ignoblekeygen.pyw
|
||||
script, you can put those keyfiles into Calibre's configuration directory. The easiest
|
||||
way to find the correct directory is to go to Calibre's Preferences page... click
|
||||
on the 'Miscellaneous' button (looks like a gear), and then click the 'Open Calibre
|
||||
configuration directory' button. Paste your keyfiles in there. Just make sure that
|
||||
they have different names and are saved with the '.b64' extension (like the ignoblekeygen
|
||||
script produces). This directory isn't touched when upgrading Calibre, so it's quite safe
|
||||
to leave then there.
|
||||
|
||||
All keyfiles from method 2 and all data entered from method 1 will be used to attempt
|
||||
to decrypt a book. You can use method 1 or method 2, or a combination of both.
|
||||
|
||||
Troubleshooting:
|
||||
|
||||
If you find that it's not working for you (imported epubs still have DRM), you can
|
||||
save a lot of time and trouble by trying to add the epub to Calibre with the command
|
||||
line tools. This will print out a lot of helpful debugging info that can be copied into
|
||||
any online help requests. I'm going to ask you to do it first, anyway, so you might
|
||||
as well get used to it. ;)
|
||||
|
||||
Open a command prompt (terminal) and change to the directory where the ebook you're
|
||||
trying to import resides. Then type the command "calibredb add your_ebook.epub".
|
||||
Don't type the quotes and obviously change the 'your_ebook.epub' to whatever the
|
||||
filename of your book is. Copy the resulting output and paste it into any online
|
||||
help request you make.
|
||||
|
||||
** Note: the Mac version of Calibre doesn't install the command line tools by default.
|
||||
If you go to the 'Preferences' page and click on the miscellaneous button, you'll
|
||||
see the option to install the command line tools.
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# ignobleepub_v01_plugin.py
|
||||
# ignobleepub_plugin.py
|
||||
# Released under the terms of the GNU General Public Licence, version 3 or
|
||||
# later. <http://www.gnu.org/licenses/>
|
||||
#
|
||||
@@ -41,7 +41,9 @@
|
||||
#
|
||||
#
|
||||
# Revision history:
|
||||
# 0.1 - Initial release
|
||||
# 0.1.0 - Initial release
|
||||
# 0.1.1 - Allow Windows users to make use of openssl if they have it installed.
|
||||
# - Incorporated SomeUpdates zipfix routine.
|
||||
|
||||
|
||||
"""
|
||||
@@ -77,7 +79,10 @@ def _load_crypto_libcrypto():
|
||||
Structure, c_ulong, create_string_buffer, cast
|
||||
from ctypes.util import find_library
|
||||
|
||||
libcrypto = find_library('crypto')
|
||||
if sys.platform.startswith('win'):
|
||||
libcrypto = find_library('libeay32')
|
||||
else:
|
||||
libcrypto = find_library('crypto')
|
||||
if libcrypto is None:
|
||||
raise IGNOBLEError('libcrypto not found')
|
||||
libcrypto = CDLL(libcrypto)
|
||||
@@ -261,7 +266,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, 0)
|
||||
version = (0, 1, 1)
|
||||
minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions.
|
||||
file_types = set(['epub'])
|
||||
on_import = True
|
||||
@@ -277,13 +282,12 @@ class IgnobleDeDRM(FileTypePlugin):
|
||||
# Add the included pycrypto import directory for Windows users.
|
||||
pdir = 'windows' if iswindows else 'osx' if isosx else 'linux'
|
||||
ppath = os.path.join(self.sys_insertion_path, pdir)
|
||||
#sys.path.insert(0, ppath)
|
||||
sys.path.append(ppath)
|
||||
|
||||
AES, AES2 = _load_crypto()
|
||||
|
||||
if AES == None or AES2 == None:
|
||||
# Failed to load libcrypto or PyCrypto... Adobe Epubs can\'t be decrypted.'
|
||||
# Failed to load libcrypto or PyCrypto... Adobe Epubs can't be decrypted.'
|
||||
sys.path.remove(ppath)
|
||||
raise IGNOBLEError('IgnobleEpub - Failed to load crypto libs.')
|
||||
return
|
||||
@@ -337,10 +341,19 @@ class IgnobleDeDRM(FileTypePlugin):
|
||||
# Attempt to decrypt epub with each encryption key (generated or provided).
|
||||
for userkey in userkeys:
|
||||
# Create a TemporaryPersistent file to work with.
|
||||
# Check original epub archive for zip errors.
|
||||
import zipfix
|
||||
inf = self.temporary_file('.epub')
|
||||
try:
|
||||
fr = zipfix.fixZip(path_to_ebook, inf.name)
|
||||
fr.fix()
|
||||
except Exception, e:
|
||||
raise Exception(e)
|
||||
return
|
||||
of = self.temporary_file('.epub')
|
||||
|
||||
# Give the user key, ebook and TemporaryPersistent file to the Stripper function.
|
||||
result = plugin_main(userkey, path_to_ebook, of.name)
|
||||
result = plugin_main(userkey, inf.name, of.name)
|
||||
|
||||
# Ebook is not a B&N Adept epub... do nothing and pass it on.
|
||||
# This allows a non-encrypted epub to be imported without error messages.
|
||||
@@ -372,4 +385,4 @@ class IgnobleDeDRM(FileTypePlugin):
|
||||
|
||||
|
||||
def customization_help(self, gui=False):
|
||||
return 'Enter B&N Account name and CC# (separate name and CC# with a comma)'
|
||||
return 'Enter B&N Account name and CC# (separate name and CC# with a comma)'
|
||||
|
||||
BIN
Calibre_Plugins/ignobleepub_plugin/windows/Crypto/Cipher/AES.pyd
Normal file
BIN
Calibre_Plugins/ignobleepub_plugin/windows/Crypto/Cipher/AES.pyd
Normal file
Binary file not shown.
136
Calibre_Plugins/ignobleepub_plugin/zipfix.py
Normal file
136
Calibre_Plugins/ignobleepub_plugin/zipfix.py
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import zlib
|
||||
import zipfile
|
||||
import os
|
||||
import os.path
|
||||
import getopt
|
||||
from struct import unpack
|
||||
|
||||
|
||||
_FILENAME_LEN_OFFSET = 26
|
||||
_EXTRA_LEN_OFFSET = 28
|
||||
_FILENAME_OFFSET = 30
|
||||
_MAX_SIZE = 64 * 1024
|
||||
|
||||
class fixZip:
|
||||
def __init__(self, zinput, zoutput):
|
||||
self.inzip = zipfile.ZipFile(zinput,'r')
|
||||
self.outzip = zipfile.ZipFile(zoutput,'w')
|
||||
# open the input zip for reading only as a raw file
|
||||
self.bzf = file(zinput,'rb')
|
||||
|
||||
def getlocalname(self, zi):
|
||||
local_header_offset = zi.header_offset
|
||||
self.bzf.seek(local_header_offset + _FILENAME_LEN_OFFSET)
|
||||
leninfo = self.bzf.read(2)
|
||||
local_name_length, = unpack('<H', leninfo)
|
||||
self.bzf.seek(local_header_offset + _FILENAME_OFFSET)
|
||||
local_name = self.bzf.read(local_name_length)
|
||||
return local_name
|
||||
|
||||
def uncompress(self, cmpdata):
|
||||
dc = zlib.decompressobj(-15)
|
||||
data = ''
|
||||
while len(cmpdata) > 0:
|
||||
if len(cmpdata) > _MAX_SIZE :
|
||||
newdata = cmpdata[0:_MAX_SIZE]
|
||||
cmpdata = cmpdata[_MAX_SIZE:]
|
||||
else:
|
||||
newdata = cmpdata
|
||||
cmpdata = ''
|
||||
newdata = dc.decompress(newdata)
|
||||
unprocessed = dc.unconsumed_tail
|
||||
if len(unprocessed) == 0:
|
||||
newdata += dc.flush()
|
||||
data += newdata
|
||||
cmpdata += unprocessed
|
||||
unprocessed = ''
|
||||
return data
|
||||
|
||||
def getfiledata(self, zi):
|
||||
# get file name length and exta data length to find start of file data
|
||||
local_header_offset = zi.header_offset
|
||||
|
||||
self.bzf.seek(local_header_offset + _FILENAME_LEN_OFFSET)
|
||||
leninfo = self.bzf.read(2)
|
||||
local_name_length, = unpack('<H', leninfo)
|
||||
|
||||
self.bzf.seek(local_header_offset + _EXTRA_LEN_OFFSET)
|
||||
exinfo = self.bzf.read(2)
|
||||
extra_field_length, = unpack('<H', exinfo)
|
||||
|
||||
self.bzf.seek(local_header_offset + _FILENAME_OFFSET + local_name_length + extra_field_length)
|
||||
data = None
|
||||
|
||||
# if not compressed we are good to go
|
||||
if zi.compress_type == zipfile.ZIP_STORED:
|
||||
data = self.bzf.read(zi.file_size)
|
||||
|
||||
# if compressed we must decompress it using zlib
|
||||
if zi.compress_type == zipfile.ZIP_DEFLATED:
|
||||
cmpdata = self.bzf.read(zi.compress_size)
|
||||
data = self.uncompress(cmpdata)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
def fix(self):
|
||||
# get the zipinfo for each member of the input archive
|
||||
# and copy member over to output archive
|
||||
# if problems exist with local vs central filename, fix them
|
||||
|
||||
for i, zinfo in enumerate(self.inzip.infolist()):
|
||||
data = None
|
||||
nzinfo = zinfo
|
||||
|
||||
try:
|
||||
data = self.inzip.read(zinfo)
|
||||
except zipfile.BadZipfile or zipfile.error:
|
||||
local_name = self.getlocalname(zinfo)
|
||||
data = self.getfiledata(zinfo)
|
||||
nzinfo.filename = local_name
|
||||
|
||||
nzinfo.date_time = zinfo.date_time
|
||||
nzinfo.compress_type = zinfo.compress_type
|
||||
nzinfo.flag_bits = 0
|
||||
nzinfo.internal_attr = 0
|
||||
self.outzip.writestr(nzinfo,data)
|
||||
|
||||
self.bzf.close()
|
||||
self.inzip.close()
|
||||
self.outzip.close()
|
||||
|
||||
|
||||
def usage():
|
||||
print """usage: zipfix.py inputzip outputzip
|
||||
inputzip is the source zipfile to fix
|
||||
outputzip is the fixed zip archive
|
||||
"""
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
if len(argv)!=3:
|
||||
usage()
|
||||
return 1
|
||||
infile = None
|
||||
outfile = None
|
||||
infile = argv[1]
|
||||
outfile = argv[2]
|
||||
if not os.path.exists(infile):
|
||||
print "Error: Input Zip File does not exist"
|
||||
return 1
|
||||
try:
|
||||
fr = fixZip(infile, outfile)
|
||||
fr.fix()
|
||||
return 0
|
||||
except Exception, e:
|
||||
print "Error Occurred ", e
|
||||
return 2
|
||||
|
||||
if __name__ == '__main__' :
|
||||
sys.exit(main())
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,62 +0,0 @@
|
||||
Inept Epub DeDRM - ineptepub_vXX_plugin.zip
|
||||
Requires Calibre version 0.6.44 or higher.
|
||||
|
||||
All credit given to I <3 Cabbages for the original standalone scripts.
|
||||
I had the much easier job of converting them to a Calibre plugin.
|
||||
|
||||
This plugin is meant to decrypt Adobe Digital Edition Epubs that are protected
|
||||
with Adobe's Adept encryption. It is meant to function without having to install
|
||||
any dependencies... other than having Calibre installed, of course. It will still
|
||||
work if you have Python and PyCrypto already installed, but they aren't necessary.
|
||||
|
||||
Installation:
|
||||
|
||||
Go to Calibre's Preferences page... click on the Plugins button. Use the file
|
||||
dialog button to select the plugin's zip file (ineptepub_vXX_plugin.zip) and
|
||||
click the 'Add' button. you're done.
|
||||
|
||||
Configuration:
|
||||
|
||||
When first run, the plugin will attempt to find your Adobe Digital Editions installation
|
||||
(on Windows and Mac OS's). If successful, it will create an 'adeptkey.der' file and
|
||||
save it in Calibre's configuration directory. It will use that file on subsequent runs.
|
||||
If there are already '*.der' files in the directory, the plugin won't attempt to
|
||||
find the Adobe Digital Editions installation installation.
|
||||
|
||||
So if you have Adobe Digital Editions installation installed on the same machine as Calibre...
|
||||
you are ready to go. If not... keep reading.
|
||||
|
||||
If you already have keyfiles generated with I <3 Cabbages' ineptkey.pyw script,
|
||||
you can put those keyfiles in Calibre's configuration directory. The easiest
|
||||
way to find the correct directory is to go to Calibre's Preferences page... click
|
||||
on the 'Miscellaneous' button (looks like a gear), and then click the 'Open Calibre
|
||||
configuration directory' button. Paste your keyfiles in there. Just make sure that
|
||||
they have different names and are saved with the '.der' extension (like the ineptkey
|
||||
script produces). This directory isn't touched when upgrading Calibre, so it's quite
|
||||
safe to leave them there.
|
||||
|
||||
Since there is no Linux version of Adobe Digital Editions, Linux users will have to
|
||||
obtain a keyfile through other methods and put the file in Calibre's configuration directory.
|
||||
|
||||
All keyfiles with a '.der' extension found in Calibre's configuration directory will
|
||||
be used to attempt to decrypt a book.
|
||||
|
||||
** NOTE ** There is no plugin customization data for the Inept Epub DeDRM plugin.
|
||||
|
||||
Troubleshooting:
|
||||
|
||||
If you find that it's not working for you (imported epubs still have DRM), you can
|
||||
save a lot of time and trouble by trying to add the epub to Calibre with the command
|
||||
line tools. This will print out a lot of helpful debugging info that can be copied into
|
||||
any online help requests. I'm going to ask you to do it first, anyway, so you might
|
||||
as well get used to it. ;)
|
||||
|
||||
Open a command prompt (terminal) and change to the directory where the ebook you're
|
||||
trying to import resides. Then type the command "calibredb add your_ebook.epub".
|
||||
Don't type the quotes and obviously change the 'your_ebook.epub' to whatever the
|
||||
filename of your book is. Copy the resulting output and paste it into any online
|
||||
help request you make.
|
||||
|
||||
** Note: the Mac version of Calibre doesn't install the command line tools by default.
|
||||
If you go to the 'Preferences' page and click on the miscellaneous button, you'll
|
||||
see the option to install the command line tools.
|
||||
@@ -19,24 +19,86 @@ class ADEPTError(Exception):
|
||||
if iswindows:
|
||||
from ctypes import windll, c_char_p, c_wchar_p, c_uint, POINTER, byref, \
|
||||
create_unicode_buffer, create_string_buffer, CFUNCTYPE, addressof, \
|
||||
string_at, Structure, c_void_p, cast, c_size_t, memmove
|
||||
string_at, Structure, c_void_p, cast, c_size_t, memmove, CDLL, c_int, \
|
||||
c_long, c_ulong
|
||||
|
||||
from ctypes.wintypes import LPVOID, DWORD, BOOL
|
||||
import _winreg as winreg
|
||||
|
||||
def _load_crypto_libcrypto():
|
||||
from ctypes.util import find_library
|
||||
libcrypto = find_library('libeay32')
|
||||
if libcrypto is None:
|
||||
raise ADEPTError('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)
|
||||
|
||||
try:
|
||||
from Crypto.Cipher import AES as _aes
|
||||
except ImportError:
|
||||
_aes = None
|
||||
def F(restype, name, argtypes):
|
||||
func = getattr(libcrypto, name)
|
||||
func.restype = restype
|
||||
func.argtypes = argtypes
|
||||
return func
|
||||
|
||||
AES_set_decrypt_key = F(c_int, 'AES_set_decrypt_key',
|
||||
[c_char_p, c_int, AES_KEY_p])
|
||||
AES_cbc_encrypt = F(None, 'AES_cbc_encrypt',
|
||||
[c_char_p, c_char_p, c_ulong, AES_KEY_p, c_char_p,
|
||||
c_int])
|
||||
class AES(object):
|
||||
def __init__(self, userkey):
|
||||
self._blocksize = len(userkey)
|
||||
if (self._blocksize != 16) and (self._blocksize != 24) and (self._blocksize != 32) :
|
||||
raise ADEPTError('AES improper key used')
|
||||
key = self._key = AES_KEY()
|
||||
rv = AES_set_decrypt_key(userkey, len(userkey) * 8, key)
|
||||
if rv < 0:
|
||||
raise ADEPTError('Failed to initialize AES key')
|
||||
def decrypt(self, data):
|
||||
out = create_string_buffer(len(data))
|
||||
iv = ("\x00" * self._blocksize)
|
||||
rv = AES_cbc_encrypt(data, out, len(data), self._key, iv, 0)
|
||||
if rv == 0:
|
||||
raise ADEPTError('AES decryption failed')
|
||||
return out.raw
|
||||
return AES
|
||||
|
||||
def _load_crypto_pycrypto():
|
||||
from Crypto.Cipher import AES as _AES
|
||||
class AES(object):
|
||||
def __init__(self, key):
|
||||
self._aes = _AES.new(key, _AES.MODE_CBC)
|
||||
def decrypt(self, data):
|
||||
return self._aes.decrypt(data)
|
||||
return AES
|
||||
|
||||
def _load_crypto():
|
||||
AES = None
|
||||
for loader in (_load_crypto_libcrypto, _load_crypto_pycrypto):
|
||||
try:
|
||||
AES = loader()
|
||||
break
|
||||
except (ImportError, ADEPTError):
|
||||
pass
|
||||
return AES
|
||||
|
||||
AES = _load_crypto()
|
||||
|
||||
|
||||
DEVICE_KEY_PATH = r'Software\Adobe\Adept\Device'
|
||||
PRIVATE_LICENCE_KEY_PATH = r'Software\Adobe\Adept\Activation'
|
||||
|
||||
|
||||
MAX_PATH = 255
|
||||
|
||||
|
||||
kernel32 = windll.kernel32
|
||||
advapi32 = windll.advapi32
|
||||
crypt32 = windll.crypt32
|
||||
|
||||
|
||||
def GetSystemDirectory():
|
||||
GetSystemDirectoryW = kernel32.GetSystemDirectoryW
|
||||
GetSystemDirectoryW.argtypes = [c_wchar_p, c_uint]
|
||||
@@ -47,7 +109,7 @@ if iswindows:
|
||||
return buffer.value
|
||||
return GetSystemDirectory
|
||||
GetSystemDirectory = GetSystemDirectory()
|
||||
|
||||
|
||||
def GetVolumeSerialNumber():
|
||||
GetVolumeInformationW = kernel32.GetVolumeInformationW
|
||||
GetVolumeInformationW.argtypes = [c_wchar_p, c_wchar_p, c_uint,
|
||||
@@ -61,7 +123,7 @@ if iswindows:
|
||||
return vsn.value
|
||||
return GetVolumeSerialNumber
|
||||
GetVolumeSerialNumber = GetVolumeSerialNumber()
|
||||
|
||||
|
||||
def GetUserName():
|
||||
GetUserNameW = advapi32.GetUserNameW
|
||||
GetUserNameW.argtypes = [c_wchar_p, POINTER(c_uint)]
|
||||
@@ -75,11 +137,11 @@ if iswindows:
|
||||
return buffer.value.encode('utf-16-le')[::2]
|
||||
return GetUserName
|
||||
GetUserName = GetUserName()
|
||||
|
||||
|
||||
PAGE_EXECUTE_READWRITE = 0x40
|
||||
MEM_COMMIT = 0x1000
|
||||
MEM_RESERVE = 0x2000
|
||||
|
||||
|
||||
def VirtualAlloc():
|
||||
_VirtualAlloc = kernel32.VirtualAlloc
|
||||
_VirtualAlloc.argtypes = [LPVOID, c_size_t, DWORD, DWORD]
|
||||
@@ -89,9 +151,9 @@ if iswindows:
|
||||
return _VirtualAlloc(addr, size, alloctype, protect)
|
||||
return VirtualAlloc
|
||||
VirtualAlloc = VirtualAlloc()
|
||||
|
||||
|
||||
MEM_RELEASE = 0x8000
|
||||
|
||||
|
||||
def VirtualFree():
|
||||
_VirtualFree = kernel32.VirtualFree
|
||||
_VirtualFree.argtypes = [LPVOID, c_size_t, DWORD]
|
||||
@@ -100,22 +162,22 @@ if iswindows:
|
||||
return _VirtualFree(addr, size, freetype)
|
||||
return VirtualFree
|
||||
VirtualFree = VirtualFree()
|
||||
|
||||
|
||||
class NativeFunction(object):
|
||||
def __init__(self, restype, argtypes, insns):
|
||||
self._buf = buf = VirtualAlloc(None, len(insns))
|
||||
memmove(buf, insns, len(insns))
|
||||
ftype = CFUNCTYPE(restype, *argtypes)
|
||||
self._native = ftype(buf)
|
||||
|
||||
|
||||
def __call__(self, *args):
|
||||
return self._native(*args)
|
||||
|
||||
|
||||
def __del__(self):
|
||||
if self._buf is not None:
|
||||
VirtualFree(self._buf)
|
||||
self._buf = None
|
||||
|
||||
|
||||
if struct.calcsize("P") == 4:
|
||||
CPUID0_INSNS = (
|
||||
"\x53" # push %ebx
|
||||
@@ -157,7 +219,7 @@ if iswindows:
|
||||
"\x5b" # pop %rbx
|
||||
"\xc3" # retq
|
||||
)
|
||||
|
||||
|
||||
def cpuid0():
|
||||
_cpuid0 = NativeFunction(None, [c_char_p], CPUID0_INSNS)
|
||||
buf = create_string_buffer(12)
|
||||
@@ -166,14 +228,14 @@ if iswindows:
|
||||
return buf.raw
|
||||
return cpuid0
|
||||
cpuid0 = cpuid0()
|
||||
|
||||
|
||||
cpuid1 = NativeFunction(c_uint, [], CPUID1_INSNS)
|
||||
|
||||
|
||||
class DataBlob(Structure):
|
||||
_fields_ = [('cbData', c_uint),
|
||||
('pbData', c_void_p)]
|
||||
DataBlob_p = POINTER(DataBlob)
|
||||
|
||||
|
||||
def CryptUnprotectData():
|
||||
_CryptUnprotectData = crypt32.CryptUnprotectData
|
||||
_CryptUnprotectData.argtypes = [DataBlob_p, c_wchar_p, DataBlob_p,
|
||||
@@ -191,10 +253,14 @@ if iswindows:
|
||||
return string_at(outdata.pbData, outdata.cbData)
|
||||
return CryptUnprotectData
|
||||
CryptUnprotectData = CryptUnprotectData()
|
||||
|
||||
|
||||
def retrieve_key():
|
||||
if _aes is None:
|
||||
raise ADEPTError("Couldn\'t load PyCrypto")
|
||||
if AES is None:
|
||||
tkMessageBox.showerror(
|
||||
"ADEPT Key",
|
||||
"This script requires PyCrypto or OpenSSL which must be installed "
|
||||
"separately. Read the top-of-script comment for details.")
|
||||
return False
|
||||
root = GetSystemDirectory().split('\\')[0] + '\\'
|
||||
serial = GetVolumeSerialNumber(root)
|
||||
vendor = cpuid0()
|
||||
@@ -236,7 +302,8 @@ if iswindows:
|
||||
if userkey is None:
|
||||
raise ADEPTError('Could not locate privateLicenseKey')
|
||||
userkey = userkey.decode('base64')
|
||||
userkey = _aes.new(keykey, _aes.MODE_CBC).decrypt(userkey)
|
||||
aes = AES(keykey)
|
||||
userkey = aes.decrypt(userkey)
|
||||
userkey = userkey[26:-ord(userkey[-1])]
|
||||
return userkey
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /usr/bin/python
|
||||
|
||||
# ineptepub_v01_plugin.py
|
||||
# ineptepub_plugin.py
|
||||
# Released under the terms of the GNU General Public Licence, version 3 or
|
||||
# later. <http://www.gnu.org/licenses/>
|
||||
#
|
||||
@@ -41,6 +41,8 @@
|
||||
#
|
||||
# Revision history:
|
||||
# 0.1 - Initial release
|
||||
# 0.1.1 - Allow Windows users to make use of openssl if they have it installed.
|
||||
# - Incorporated SomeUpdates zipfix routine.
|
||||
|
||||
|
||||
"""
|
||||
@@ -76,7 +78,10 @@ def _load_crypto_libcrypto():
|
||||
Structure, c_ulong, create_string_buffer, cast
|
||||
from ctypes.util import find_library
|
||||
|
||||
libcrypto = find_library('crypto')
|
||||
if sys.platform.startswith('win'):
|
||||
libcrypto = find_library('libeay32')
|
||||
else:
|
||||
libcrypto = find_library('crypto')
|
||||
if libcrypto is None:
|
||||
raise ADEPTError('libcrypto not found')
|
||||
libcrypto = CDLL(libcrypto)
|
||||
@@ -358,7 +363,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, 0)
|
||||
version = (0, 1, 1)
|
||||
minimum_calibre_version = (0, 6, 44) # Compiled python libraries cannot be imported in earlier versions.
|
||||
file_types = set(['epub'])
|
||||
on_import = True
|
||||
@@ -376,7 +381,6 @@ class IneptDeDRM(FileTypePlugin):
|
||||
# Add the included Carbon import directory for Mac users.
|
||||
pdir = 'windows' if iswindows else 'osx' if isosx else 'linux'
|
||||
ppath = os.path.join(self.sys_insertion_path, pdir)
|
||||
#sys.path.insert(0, ppath)
|
||||
sys.path.append(ppath)
|
||||
|
||||
AES, RSA = _load_crypto()
|
||||
@@ -433,10 +437,19 @@ class IneptDeDRM(FileTypePlugin):
|
||||
# Attempt to decrypt epub with each encryption key found.
|
||||
for userkey in userkeys:
|
||||
# Create a TemporaryPersistent file to work with.
|
||||
# Check original epub archive for zip errors.
|
||||
import zipfix
|
||||
inf = self.temporary_file('.epub')
|
||||
try:
|
||||
fr = zipfix.fixZip(path_to_ebook, inf.name)
|
||||
fr.fix()
|
||||
except Exception, e:
|
||||
raise Exception(e)
|
||||
return
|
||||
of = self.temporary_file('.epub')
|
||||
|
||||
# Give the user key, ebook and TemporaryPersistent file to the plugin_main function.
|
||||
result = plugin_main(userkey, path_to_ebook, of.name)
|
||||
result = plugin_main(userkey, inf.name, of.name)
|
||||
|
||||
# Ebook is not an Adobe Adept epub... do nothing and pass it on.
|
||||
# This allows a non-encrypted epub to be imported without error messages.
|
||||
|
||||
BIN
Calibre_Plugins/ineptepub_plugin/osx/Carbon/File.pyo
Normal file
BIN
Calibre_Plugins/ineptepub_plugin/osx/Carbon/File.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/ineptepub_plugin/osx/Carbon/Folder.pyo
Normal file
BIN
Calibre_Plugins/ineptepub_plugin/osx/Carbon/Folder.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/ineptepub_plugin/osx/Carbon/Folders.pyo
Normal file
BIN
Calibre_Plugins/ineptepub_plugin/osx/Carbon/Folders.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/ineptepub_plugin/osx/Carbon/__init__.pyo
Normal file
BIN
Calibre_Plugins/ineptepub_plugin/osx/Carbon/__init__.pyo
Normal file
Binary file not shown.
BIN
Calibre_Plugins/ineptepub_plugin/windows/Crypto/Cipher/AES.pyd
Normal file
BIN
Calibre_Plugins/ineptepub_plugin/windows/Crypto/Cipher/AES.pyd
Normal file
Binary file not shown.
BIN
Calibre_Plugins/ineptepub_plugin/windows/Crypto/Hash/SHA256.pyd
Normal file
BIN
Calibre_Plugins/ineptepub_plugin/windows/Crypto/Hash/SHA256.pyd
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
136
Calibre_Plugins/ineptepub_plugin/zipfix.py
Normal file
136
Calibre_Plugins/ineptepub_plugin/zipfix.py
Normal file
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import zlib
|
||||
import zipfile
|
||||
import os
|
||||
import os.path
|
||||
import getopt
|
||||
from struct import unpack
|
||||
|
||||
|
||||
_FILENAME_LEN_OFFSET = 26
|
||||
_EXTRA_LEN_OFFSET = 28
|
||||
_FILENAME_OFFSET = 30
|
||||
_MAX_SIZE = 64 * 1024
|
||||
|
||||
class fixZip:
|
||||
def __init__(self, zinput, zoutput):
|
||||
self.inzip = zipfile.ZipFile(zinput,'r')
|
||||
self.outzip = zipfile.ZipFile(zoutput,'w')
|
||||
# open the input zip for reading only as a raw file
|
||||
self.bzf = file(zinput,'rb')
|
||||
|
||||
def getlocalname(self, zi):
|
||||
local_header_offset = zi.header_offset
|
||||
self.bzf.seek(local_header_offset + _FILENAME_LEN_OFFSET)
|
||||
leninfo = self.bzf.read(2)
|
||||
local_name_length, = unpack('<H', leninfo)
|
||||
self.bzf.seek(local_header_offset + _FILENAME_OFFSET)
|
||||
local_name = self.bzf.read(local_name_length)
|
||||
return local_name
|
||||
|
||||
def uncompress(self, cmpdata):
|
||||
dc = zlib.decompressobj(-15)
|
||||
data = ''
|
||||
while len(cmpdata) > 0:
|
||||
if len(cmpdata) > _MAX_SIZE :
|
||||
newdata = cmpdata[0:_MAX_SIZE]
|
||||
cmpdata = cmpdata[_MAX_SIZE:]
|
||||
else:
|
||||
newdata = cmpdata
|
||||
cmpdata = ''
|
||||
newdata = dc.decompress(newdata)
|
||||
unprocessed = dc.unconsumed_tail
|
||||
if len(unprocessed) == 0:
|
||||
newdata += dc.flush()
|
||||
data += newdata
|
||||
cmpdata += unprocessed
|
||||
unprocessed = ''
|
||||
return data
|
||||
|
||||
def getfiledata(self, zi):
|
||||
# get file name length and exta data length to find start of file data
|
||||
local_header_offset = zi.header_offset
|
||||
|
||||
self.bzf.seek(local_header_offset + _FILENAME_LEN_OFFSET)
|
||||
leninfo = self.bzf.read(2)
|
||||
local_name_length, = unpack('<H', leninfo)
|
||||
|
||||
self.bzf.seek(local_header_offset + _EXTRA_LEN_OFFSET)
|
||||
exinfo = self.bzf.read(2)
|
||||
extra_field_length, = unpack('<H', exinfo)
|
||||
|
||||
self.bzf.seek(local_header_offset + _FILENAME_OFFSET + local_name_length + extra_field_length)
|
||||
data = None
|
||||
|
||||
# if not compressed we are good to go
|
||||
if zi.compress_type == zipfile.ZIP_STORED:
|
||||
data = self.bzf.read(zi.file_size)
|
||||
|
||||
# if compressed we must decompress it using zlib
|
||||
if zi.compress_type == zipfile.ZIP_DEFLATED:
|
||||
cmpdata = self.bzf.read(zi.compress_size)
|
||||
data = self.uncompress(cmpdata)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
|
||||
def fix(self):
|
||||
# get the zipinfo for each member of the input archive
|
||||
# and copy member over to output archive
|
||||
# if problems exist with local vs central filename, fix them
|
||||
|
||||
for i, zinfo in enumerate(self.inzip.infolist()):
|
||||
data = None
|
||||
nzinfo = zinfo
|
||||
|
||||
try:
|
||||
data = self.inzip.read(zinfo)
|
||||
except zipfile.BadZipfile or zipfile.error:
|
||||
local_name = self.getlocalname(zinfo)
|
||||
data = self.getfiledata(zinfo)
|
||||
nzinfo.filename = local_name
|
||||
|
||||
nzinfo.date_time = zinfo.date_time
|
||||
nzinfo.compress_type = zinfo.compress_type
|
||||
nzinfo.flag_bits = 0
|
||||
nzinfo.internal_attr = 0
|
||||
self.outzip.writestr(nzinfo,data)
|
||||
|
||||
self.bzf.close()
|
||||
self.inzip.close()
|
||||
self.outzip.close()
|
||||
|
||||
|
||||
def usage():
|
||||
print """usage: zipfix.py inputzip outputzip
|
||||
inputzip is the source zipfile to fix
|
||||
outputzip is the fixed zip archive
|
||||
"""
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
if len(argv)!=3:
|
||||
usage()
|
||||
return 1
|
||||
infile = None
|
||||
outfile = None
|
||||
infile = argv[1]
|
||||
outfile = argv[2]
|
||||
if not os.path.exists(infile):
|
||||
print "Error: Input Zip File does not exist"
|
||||
return 1
|
||||
try:
|
||||
fr = fixZip(infile, outfile)
|
||||
fr.fix()
|
||||
return 0
|
||||
except Exception, e:
|
||||
print "Error Occurred ", e
|
||||
return 2
|
||||
|
||||
if __name__ == '__main__' :
|
||||
sys.exit(main())
|
||||
|
||||
|
||||
Binary file not shown.
@@ -43,6 +43,7 @@ import sys
|
||||
import os, csv, getopt
|
||||
import binascii
|
||||
import zlib
|
||||
import re
|
||||
from struct import pack, unpack, unpack_from
|
||||
|
||||
|
||||
@@ -115,9 +116,9 @@ def decode(data,map):
|
||||
|
||||
|
||||
# Parse the Kindle.info file and return the records as a list of key-values
|
||||
def parseKindleInfo():
|
||||
def parseKindleInfo(kInfoFile):
|
||||
DB = {}
|
||||
infoReader = openKindleInfo()
|
||||
infoReader = openKindleInfo(kInfoFile)
|
||||
infoReader.read(1)
|
||||
data = infoReader.read()
|
||||
if sys.platform.startswith('win'):
|
||||
@@ -279,10 +280,10 @@ class MobiPeek:
|
||||
|
||||
# DiapDealer's stuff: Parse the EXTH header records and parse the Kindleinfo
|
||||
# file to calculate the book pid.
|
||||
def getK4Pids(exth, title):
|
||||
def getK4Pids(exth, title, kInfoFile=None):
|
||||
global kindleDatabase
|
||||
try:
|
||||
kindleDatabase = parseKindleInfo()
|
||||
kindleDatabase = parseKindleInfo(kInfoFile)
|
||||
except Exception as message:
|
||||
print(message)
|
||||
|
||||
@@ -353,30 +354,49 @@ def getK4Pids(exth, title):
|
||||
raise DrmException("\nCould not access K4 data - Perhaps K4 is not installed/configured?")
|
||||
return null
|
||||
|
||||
def usage(progname):
|
||||
print "Removes DRM protection from K4PC, K4M, and Mobi ebooks"
|
||||
print "Usage:"
|
||||
print " %s [-k <kindle.info>] [-p <pidnums>] <infile> <outfile> " % progname
|
||||
|
||||
#
|
||||
# Main
|
||||
#
|
||||
def main(argv=sys.argv):
|
||||
global kindleDatabase
|
||||
import mobidedrm
|
||||
|
||||
progname = os.path.basename(argv[0])
|
||||
kInfoFiles = []
|
||||
pidnums = ""
|
||||
|
||||
print ('K4MobiDeDrm v%(__version__)s '
|
||||
'provided by the work of many including DiapDealer, SomeUpdates, IHeartCabbages, CMBDTC, Skindle, DarkReverser, ApprenticeAlf, etc .' % globals())
|
||||
|
||||
if len(argv)<3:
|
||||
print "Removes DRM protection from K4PC, K4M, and Mobi ebooks"
|
||||
print "Usage:"
|
||||
print " %s <infile> <outfile> [<pidnums>]" % argv[0]
|
||||
return 1
|
||||
|
||||
if len(argv) == 4:
|
||||
pidnums = argv[3]
|
||||
|
||||
if len(argv) == 3:
|
||||
pidnums = ""
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "k:p:")
|
||||
except getopt.GetoptError, err:
|
||||
print str(err)
|
||||
usage(progname)
|
||||
sys.exit(2)
|
||||
|
||||
if len(args)<2:
|
||||
usage(progname)
|
||||
sys.exit(2)
|
||||
|
||||
for o, a in opts:
|
||||
if o == "-k":
|
||||
if a == None :
|
||||
raise DrmException("Invalid parameter for -k")
|
||||
kInfoFiles.append(a)
|
||||
if o == "-p":
|
||||
if a == None :
|
||||
raise DrmException("Invalid parameter for -p")
|
||||
pidnums = a
|
||||
|
||||
kindleDatabase = None
|
||||
infile = argv[1]
|
||||
outfile = argv[2]
|
||||
infile = args[0]
|
||||
outfile = args[1]
|
||||
try:
|
||||
# first try with K4PC/K4M
|
||||
ex = MobiPeek(infile)
|
||||
@@ -394,8 +414,25 @@ def main(argv=sys.argv):
|
||||
else:
|
||||
file(outfile, 'wb').write(unlocked_file)
|
||||
return 0
|
||||
|
||||
# now try from the pid list
|
||||
|
||||
# now try alternate kindle.info files
|
||||
if kInfoFiles:
|
||||
for infoFile in kInfoFiles:
|
||||
kindleDatabase = None
|
||||
try:
|
||||
title = ex.getBookTitle()
|
||||
exth = ex.getexthData()
|
||||
pid = getK4Pids(exth, title, infoFile)
|
||||
unlocked_file = mobidedrm.getUnencryptedBook(infile, pid)
|
||||
except DrmException:
|
||||
pass
|
||||
except mobidedrm.DrmException:
|
||||
pass
|
||||
else:
|
||||
file(outfile, 'wb').write(unlocked_file)
|
||||
return 0
|
||||
|
||||
# Lastly, try from the pid list
|
||||
pids = pidnums.split(',')
|
||||
for pid in pids:
|
||||
try:
|
||||
@@ -426,7 +463,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, 0, 1) # The version number of this plugin
|
||||
version = (0, 1, 1) # The version number of this plugin
|
||||
file_types = set(['prc','mobi','azw']) # The file types that this plugin will be applied to
|
||||
on_import = True # Run this plugin during the import
|
||||
priority = 200 # run this plugin before mobidedrm, k4pcdedrm, k4dedrm
|
||||
@@ -442,7 +479,27 @@ if not __name__ == "__main__" and inCalibre:
|
||||
from k4mutils import openKindleInfo, CryptUnprotectData, GetUserName, GetVolumeSerialNumber, charMap1, charMap2, charMap3, charMap4
|
||||
import mobidedrm
|
||||
|
||||
# Get supplied list of PIDs to try from plugin customization.
|
||||
pidnums = self.site_customization
|
||||
|
||||
# Load any kindle info files (*.info) included Calibre's config directory.
|
||||
kInfoFiles = []
|
||||
try:
|
||||
# Find Calibre's configuration directory.
|
||||
confpath = os.path.split(os.path.split(self.plugin_path)[0])[0]
|
||||
print 'K4MobiDeDRM: Calibre configuration directory = %s' % confpath
|
||||
files = os.listdir(confpath)
|
||||
filefilter = re.compile("\.info$", re.IGNORECASE)
|
||||
files = filter(filefilter.search, files)
|
||||
|
||||
if files:
|
||||
for filename in files:
|
||||
fpath = os.path.join(confpath, filename)
|
||||
kInfoFiles.append(fpath)
|
||||
print 'K4MobiDeDRM: Kindle info file %s found in config folder.' % filename
|
||||
except IOError:
|
||||
print 'K4MobiDeDRM: Error reading kindle info files from config directory.'
|
||||
pass
|
||||
|
||||
# first try with book specifc pid from K4PC or K4M
|
||||
try:
|
||||
@@ -463,6 +520,25 @@ if not __name__ == "__main__" and inCalibre:
|
||||
of.write(unlocked_file)
|
||||
of.close()
|
||||
return of.name
|
||||
|
||||
# Now try alternate kindle info files
|
||||
if kInfoFiles:
|
||||
for infoFile in kInfoFiles:
|
||||
kindleDatabase = None
|
||||
try:
|
||||
title = ex.getBookTitle()
|
||||
exth = ex.getexthData()
|
||||
pid = getK4Pids(exth, title, infoFile)
|
||||
unlocked_file = mobidedrm.getUnencryptedBook(path_to_ebook,pid)
|
||||
except DrmException:
|
||||
pass
|
||||
except mobidedrm.DrmException:
|
||||
pass
|
||||
else:
|
||||
of = self.temporary_file('.mobi')
|
||||
of.write(unlocked_file)
|
||||
of.close()
|
||||
return of.name
|
||||
|
||||
# now try from the pid list
|
||||
pids = pidnums.split(',')
|
||||
|
||||
@@ -298,22 +298,25 @@ def CryptUnprotectData(encryptedData):
|
||||
return cleartext
|
||||
|
||||
# Locate and open the .kindle-info file
|
||||
def openKindleInfo():
|
||||
home = os.getenv('HOME')
|
||||
cmdline = 'find "' + home + '/Library/Application Support" -name ".kindle-info"'
|
||||
cmdline = cmdline.encode(sys.getfilesystemencoding())
|
||||
p1 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
|
||||
poll = p1.wait('wait')
|
||||
results = p1.read()
|
||||
reslst = results.split('\n')
|
||||
kinfopath = 'NONE'
|
||||
cnt = len(reslst)
|
||||
for j in xrange(cnt):
|
||||
resline = reslst[j]
|
||||
pp = resline.find('.kindle-info')
|
||||
if pp >= 0:
|
||||
kinfopath = resline
|
||||
break
|
||||
if not os.path.exists(kinfopath):
|
||||
raise K4MDrmException('Error: .kindle-info file can not be found')
|
||||
return open(kinfopath,'r')
|
||||
def openKindleInfo(kInfoFile=None):
|
||||
if kInfoFile == None:
|
||||
home = os.getenv('HOME')
|
||||
cmdline = 'find "' + home + '/Library/Application Support" -name ".kindle-info"'
|
||||
cmdline = cmdline.encode(sys.getfilesystemencoding())
|
||||
p1 = Process(cmdline, shell=True, bufsize=1, stdin=None, stdout=PIPE, stderr=PIPE, close_fds=False)
|
||||
poll = p1.wait('wait')
|
||||
results = p1.read()
|
||||
reslst = results.split('\n')
|
||||
kinfopath = 'NONE'
|
||||
cnt = len(reslst)
|
||||
for j in xrange(cnt):
|
||||
resline = reslst[j]
|
||||
pp = resline.find('.kindle-info')
|
||||
if pp >= 0:
|
||||
kinfopath = resline
|
||||
break
|
||||
if not os.path.exists(kinfopath):
|
||||
raise K4MDrmException('Error: .kindle-info file can not be found')
|
||||
return open(kinfopath,'r')
|
||||
else:
|
||||
return open(kInfoFile, 'r')
|
||||
@@ -101,7 +101,10 @@ CryptUnprotectData = CryptUnprotectData()
|
||||
#
|
||||
# Locate and open the Kindle.info file.
|
||||
#
|
||||
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')
|
||||
def openKindleInfo(kInfoFile=None):
|
||||
if kInfoFile == None:
|
||||
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')
|
||||
else:
|
||||
return open(kInfoFile, 'r')
|
||||
|
||||
@@ -37,14 +37,17 @@
|
||||
# in utf8 file are encrypted. (Although neither kind gets compressed.)
|
||||
# This knowledge leads to a simplification of the test for the
|
||||
# trailing data byte flags - version 5 and higher AND header size >= 0xE4.
|
||||
# 0.15 - Now outputs 'hearbeat', and is also quicker for long files.
|
||||
# 0.15 - Now outputs 'heartbeat', and is also quicker for long files.
|
||||
# 0.16 - And reverts to 'done' not 'done.' at the end for unswindle compatibility.
|
||||
# 0.17 - added modifications to support its use as an imported python module
|
||||
# both inside calibre and also in other places (ie K4DeDRM tools)
|
||||
# 0.17a - disabled the standalone plugin feature since a plugin can not import
|
||||
# 0.17a- disabled the standalone plugin feature since a plugin can not import
|
||||
# a plugin
|
||||
# 0.18 - It seems that multibyte entries aren't encrypted in a v7 file...
|
||||
# Removed the disabled Calibre plug-in code
|
||||
# Permit use of 8-digit PIDs
|
||||
|
||||
__version__ = '0.17'
|
||||
__version__ = '0.18'
|
||||
|
||||
import sys
|
||||
import struct
|
||||
@@ -127,10 +130,11 @@ def getSizeOfTrailingDataEntries(ptr, size, flags):
|
||||
if testflags & 1:
|
||||
num += getSizeOfTrailingDataEntry(ptr, size - num)
|
||||
testflags >>= 1
|
||||
# Multibyte data, if present, is included in the encryption, so
|
||||
# we do not need to check the low bit.
|
||||
# if flags & 1:
|
||||
# num += (ord(ptr[size - num - 1]) & 0x3) + 1
|
||||
# Check the low bit to see if there's multibyte data present.
|
||||
# if multibyte data is included in the encryped data, we'll
|
||||
# have already cleared this flag.
|
||||
if flags & 1:
|
||||
num += (ord(ptr[size - num - 1]) & 0x3) + 1
|
||||
return num
|
||||
|
||||
class DrmStripper:
|
||||
@@ -181,9 +185,14 @@ class DrmStripper:
|
||||
return found_key
|
||||
|
||||
def __init__(self, data_file, pid):
|
||||
if checksumPid(pid[0:-2]) != pid:
|
||||
raise DrmException("invalid PID checksum")
|
||||
pid = pid[0:-2]
|
||||
if len(pid)==10:
|
||||
if checksumPid(pid[0:-2]) != pid:
|
||||
raise DrmException("invalid PID checksum")
|
||||
pid = pid[0:-2]
|
||||
elif len(pid)==8:
|
||||
print "PID without checksum given. With checksum PID is "+checksumPid(pid)
|
||||
else:
|
||||
raise DrmException("Invalid PID length")
|
||||
|
||||
self.data_file = data_file
|
||||
header = data_file[0:72]
|
||||
@@ -206,6 +215,10 @@ class DrmStripper:
|
||||
if (mobi_length >= 0xE4) and (mobi_version >= 5):
|
||||
extra_data_flags, = struct.unpack('>H', sect[0xF2:0xF4])
|
||||
print "Extra Data Flags = %d" %extra_data_flags
|
||||
if mobi_version < 7:
|
||||
# multibyte utf8 data is included in the encryption for mobi_version 5 (& 6?)
|
||||
# so clear that byte so that we leave it to be decrypted.
|
||||
extra_data_flags &= 0xFFFE
|
||||
|
||||
crypto_type, = struct.unpack('>H', sect[0xC:0xC+2])
|
||||
if crypto_type == 0:
|
||||
@@ -282,44 +295,3 @@ def main(argv=sys.argv):
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
#if not __name__ == "__main__":
|
||||
if False:
|
||||
|
||||
# note a calibre plugin can not import code with another calibre plugin
|
||||
# in it as it ends up registering two different plugins
|
||||
from calibre.customize import FileTypePlugin
|
||||
|
||||
class MobiDeDRM(FileTypePlugin):
|
||||
name = 'MobiDeDRM' # Name of the plugin
|
||||
description = 'Removes DRM from secure Mobi files'
|
||||
supported_platforms = ['linux', 'osx', 'windows'] # Platforms this plugin will run on
|
||||
author = 'The Dark Reverser' # The author of this plugin
|
||||
version = (0, 1, 7) # The version number of this plugin
|
||||
file_types = set(['prc','mobi','azw']) # The file types that this plugin will be applied to
|
||||
on_import = True # Run this plugin during the import
|
||||
|
||||
def run(self, path_to_ebook):
|
||||
from calibre.gui2 import is_ok_to_use_qt
|
||||
from PyQt4.Qt import QMessageBox
|
||||
PID = self.site_customization
|
||||
data_file = file(path_to_ebook, 'rb').read()
|
||||
ar = PID.split(',')
|
||||
for i in ar:
|
||||
try:
|
||||
unlocked_file = DrmStripper(data_file, i).getResult()
|
||||
except DrmException:
|
||||
if is_ok_to_use_qt():
|
||||
d = QMessageBox(QMessageBox.Warning, "MobiDeDRM Plugin", "Error decoding: %s\n" % path_to_ebook)
|
||||
d.show()
|
||||
d.raise_()
|
||||
d.exec_()
|
||||
raise Exception("MobiDeDRM Plugin: Error decoding ebook")
|
||||
else:
|
||||
of = self.temporary_file('.mobi')
|
||||
of.write(unlocked_file)
|
||||
of.close()
|
||||
return of.name
|
||||
|
||||
def customization_help(self, gui=False):
|
||||
return 'Enter PID (separate multiple PIDs with comma)'
|
||||
|
||||
Reference in New Issue
Block a user