sync with main

This commit is contained in:
Kovid Goyal 2008-07-30 17:12:50 -07:00
commit 8f08dc92b8
62 changed files with 7997 additions and 1548 deletions

View File

@ -20,3 +20,6 @@ src/calibre/gui2/pictureflow/pictureflow_resource.rc
src/calibre/gui2/pictureflow/release/
src/calibre/translations/compiled.py
installer/windows/calibre/build.log
src/calibre/translations/.errors
src/calibre/plugins/*
src/calibre/gui2/pictureflow/.build

View File

@ -1,11 +1,6 @@
PYTHON = python
all : plugins gui2 translations resources
plugins : src/calibre/plugins pictureflow lzx
src/calibre/plugins:
mkdir -p src/calibre/plugins
all : gui2 translations resources
clean :
cd src/calibre/gui2 && ${PYTHON} make.py clean
@ -25,26 +20,6 @@ resources:
manual:
make -C src/calibre/manual clean html
pictureflow :
mkdir -p src/calibre/plugins && rm -f src/calibre/plugins/*pictureflow* && \
cd src/calibre/gui2/pictureflow && rm -f *.o && \
mkdir -p .build && cd .build && rm -f * && \
qmake ../pictureflow.pro && make staticlib && \
cd ../PyQt && \
mkdir -p .build && \
cd .build && rm -f * && \
${PYTHON} ../configure.py && make && \
cd ../../../../../.. && \
cp src/calibre/gui2/pictureflow/PyQt/.build/pictureflow.so src/calibre/plugins/ && \
rm -rf src/calibre/gui2/pictureflow/.build rm -rf src/calibre/gui2/pictureflow/PyQt/.build
lzx :
mkdir -p src/calibre/plugins && rm -f src/calibre/plugins/lzx.so && \
cd src/calibre/utils/lzx && \
${PYTHON} setup.py build --build-base=.build && cd - && \
cp src/calibre/utils/lzx/.build/lib*/lzx.so src/calibre/plugins/ && \
rm -rf src/calibre/utils/lzx/.build/
pot :
cd src/calibre/translations && ${PYTHON} __init__.py pot

View File

@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
'''
Create linux binary.
'''
import glob, sys, subprocess, tarfile, os, re, py_compile
import glob, sys, subprocess, tarfile, os, re, py_compile, shutil
HOME = '/home/kovid'
PYINSTALLER = os.path.expanduser('~/build/pyinstaller')
CALIBREPREFIX = '___'
@ -16,6 +16,9 @@ LIBUNRAR = '/usr/lib/libunrar.so'
QTDIR = '/usr/lib/qt4'
QTDLLS = ('QtCore', 'QtGui', 'QtNetwork', 'QtSvg', 'QtXml')
EXTRAS = ('/usr/lib/python2.5/site-packages/PIL', os.path.expanduser('~/ipython/IPython'))
SQLITE = '/usr/lib/libsqlite3.so.0'
DBUS = '/usr/lib/libdbus-1.so.3'
LIBMNG = '/usr/lib/libmng.so.1'
CALIBRESRC = os.path.join(CALIBREPREFIX, 'src')
@ -33,7 +36,6 @@ open(os.path.join(PYINSTALLER, 'hooks', 'hook-calibre.parallel.py'), 'wb').write
def run_pyinstaller(args=sys.argv):
subprocess.check_call(('/usr/bin/sudo', 'chown', '-R', 'kovid:users', glob.glob('/usr/lib/python*/site-packages/')[-1]))
subprocess.check_call('rm -rf %(py)s/dist/* %(py)s/build/*'%dict(py=PYINSTALLER), shell=True)
subprocess.check_call('make plugins', shell=True)
cp = HOME+'/build/'+os.path.basename(os.getcwd())
spec = open(os.path.join(PYINSTALLER, 'calibre', 'calibre.spec'), 'wb')
raw = re.sub(r'CALIBREPREFIX\s+=\s+\'___\'', 'CALIBREPREFIX = '+repr(cp),
@ -41,12 +43,14 @@ def run_pyinstaller(args=sys.argv):
spec.write(raw)
spec.close()
os.chdir(PYINSTALLER)
shutil.rmtree('calibre/dist')
os.mkdir('calibre/dist')
subprocess.check_call('python -OO Build.py calibre/calibre.spec', shell=True)
return 0
if __name__ == '__main__' and 'linux_installer.py' in __file__:
if __name__ == '__main__' and 'freeze.py' in __file__:
sys.exit(run_pyinstaller())
@ -59,7 +63,7 @@ os.chdir(os.environ.get("ORIGWD", "."))
sys.path.insert(0, os.path.join(sys.frozen_path, "library.pyz"))
sys.path.insert(0, sys.frozen_path)
from PyQt4.QtCore import QCoreApplication
QCoreApplication.setLibraryPaths([sys.frozen_path, os.path.join(sys.frozen_path, "plugins")])
QCoreApplication.setLibraryPaths([sys.frozen_path, os.path.join(sys.frozen_path, "qtplugins")])
''')
excludes = ['gtk._gtk', 'gtk.glade', 'qt', 'matplotlib.nxutils', 'matplotlib._cntr',
'matplotlib.ttconv', 'matplotlib._image', 'matplotlib.ft2font',
@ -80,7 +84,7 @@ for entry in entry_points['console_scripts'] + entry_points['gui_scripts']:
scripts.append(os.path.join(CALIBRESRC, *map(lambda x: x.strip(), fields[1].split(':')[0].split('.')))+'.py')
analyses = [Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), loader, script],
pathex=[PYINSTALLER, CALIBRESRC, CALIBREPLUGINS], excludes=excludes) for script in scripts]
pathex=[PYINSTALLER, CALIBRESRC], excludes=excludes) for script in scripts]
pyz = TOC()
binaries = TOC()
@ -104,11 +108,18 @@ for script, exe, a in zip(scripts, executables, analyses):
print 'Adding plugins...'
for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so')):
binaries += [('plugins/'+os.path.basename(f), f, 'BINARY')]
for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so.*')):
binaries += [(os.path.basename(f), f, 'BINARY')]
print 'Adding external programs...'
binaries += [('clit', CLIT, 'BINARY'), ('pdftohtml', PDFTOHTML, 'BINARY'),
('libunrar.so', LIBUNRAR, 'BINARY')]
print 'Adding external libraries...'
binaries += [ (os.path.basename(x), x, 'BINARY') for x in (SQLITE, DBUS, LIBMNG)]
qt = []
for dll in QTDLLS:
path = os.path.join(QTDIR, 'lib'+dll+'.so.4')
@ -121,7 +132,7 @@ for dirpath, dirnames, filenames in os.walk(plugdir):
for f in filenames:
if not f.endswith('.so') or 'designer' in dirpath or 'codcs' in dirpath or 'sqldrivers' in dirpath : continue
f = os.path.join(dirpath, f)
plugins.append(('plugins/'+f.replace(plugdir, ''), f, 'BINARY'))
plugins.append(('qtplugins/'+f.replace(plugdir, ''), f, 'BINARY'))
binaries += plugins
manifest = '/tmp/manifest'

View File

@ -4,7 +4,14 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
''' Create an OSX installer '''
import sys, re, os, shutil, subprocess, stat, glob, zipfile
from setup import VERSION, APPNAME, scripts, main_modules, basenames, main_functions
l = {}
exec open('setup.py').read() in l
VERSION = l['VERSION']
APPNAME = l['APPNAME']
scripts = l['scripts']
basenames = l['basenames']
main_functions = l['main_functions']
main_modules = l['main_modules']
from setuptools import setup
from py2app.build_app import py2app
from modulegraph.find_modules import find_modules
@ -38,8 +45,10 @@ print >>loader, 'from %(module)s import %(function)s'
print >>loader, '%(function)s()'
loader.close()
os.chmod(loader_path, 0700)
os.environ['PYTHONHOME'] = resources_dir
os.environ['FC_CONFIG_DIR'] = os.path.join(resources_dir, 'fonts')
os.environ['PYTHONHOME'] = resources_dir
os.environ['FC_CONFIG_DIR'] = os.path.join(resources_dir, 'fonts')
os.environ['MAGICK_HOME'] = os.path.join(frameworks_dir, 'ImageMagick')
os.environ['DYLD_LIBRARY_PATH'] = os.path.join(frameworks_dir, 'ImageMagick', 'lib')
os.execv(loader_path, sys.argv)
'''
CHECK_SYMLINKS_PRESCRIPT = \
@ -170,64 +179,46 @@ _check_symlinks_prescript()
for f in files:
subprocess.check_call(['/usr/bin/install_name_tool', '-change', '/Library/Frameworks/Python.framework/Versions/2.5/Python', '@executable_path/../Frameworks/Python.framework/Versions/2.5/Python', f])
def fix_misc_dependencies(self, files):
for path in files:
frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks')
pipe = subprocess.Popen('/usr/bin/otool -L '+path, shell=True, stdout=subprocess.PIPE).stdout
for l in pipe.readlines():
match = re.search(r'\s+(.*?)\s+\(', l)
if match:
dep = match.group(1)
name = os.path.basename(dep)
if not name:
name = dep
bundle = os.path.join(frameworks_dir, name)
if os.path.exists(bundle):
subprocess.check_call(['/usr/bin/install_name_tool', '-change', dep,
'@executable_path/../Frameworks/'+name, path])
def build_distutils_plugins(self):
plugins = [
('lzx', os.path.join('utils', 'lzx')),
]
files = []
env = {'PATH':os.environ['PATH']}
for name, path in plugins:
print 'Building plugin', name
path = os.path.abspath(os.path.join('src', 'calibre', path))
cwd = os.getcwd()
os.chdir(path)
try:
if os.path.exists('.build'):
shutil.rmtree('.build')
subprocess.check_call((sys.executable, 'setup.py', 'build', '--build-base', '.build'),
env=env)
plugin = os.path.abspath(glob.glob('.build/lib*/%s.so'%name)[0])
files.append([plugin, os.path.basename(plugin)])
finally:
os.chdir(cwd)
return files
def build_plugins(self):
cwd = os.getcwd()
qmake = '/Users/kovid/qt/bin/qmake'
files = []
try:
print 'Building pictureflow'
os.chdir('src/calibre/gui2/pictureflow')
if not os.path.exists('.build'):
os.mkdir('.build')
os.chdir('.build')
for f in glob.glob('*'): os.unlink(f)
subprocess.check_call([qmake, '../pictureflow.pro'])
subprocess.check_call(['make'])
files.append((os.path.abspath(os.path.realpath('libpictureflow.dylib')), 'libpictureflow.dylib'))
os.chdir('../PyQt')
if not os.path.exists('.build'):
os.mkdir('.build')
os.chdir('.build')
for f in glob.glob('*'): os.unlink(f)
subprocess.check_call([PYTHON, '../configure.py'])
subprocess.check_call(['/usr/bin/make'])
files.append((os.path.abspath('pictureflow.so'), 'pictureflow.so'))
subprocess.check_call(['/usr/bin/install_name_tool', '-change', 'libpictureflow.0.dylib', '@executable_path/../Frameworks/libpictureflow.dylib', 'pictureflow.so'])
self.fix_python_dependencies((files[0][0], files[1][0]))
for i in range(2):
deps = BuildAPP.qt_dependencies(files[i][0])
BuildAPP.fix_qt_dependencies(files[i][0], deps)
def add_plugins(self):
self.add_qt_plugins()
frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks')
plugins_dir = os.path.join(frameworks_dir, 'plugins')
if not os.path.exists(plugins_dir):
os.mkdir(plugins_dir)
return files
finally:
os.chdir(cwd)
maps = {}
for f in glob.glob('src/calibre/plugins/*'):
tgt = plugins_dir
if f.endswith('.dylib'):
tgt = frameworks_dir
maps[f] = os.path.join(tgt, os.path.basename(f))
deps = []
for src, dst in maps.items():
shutil.copyfile(src, dst)
self.fix_qt_dependencies(dst, self.qt_dependencies(dst))
deps.append(dst)
self.fix_python_dependencies(deps)
self.fix_misc_dependencies(deps)
def run(self):
plugin_files = self.build_distutils_plugins()
py2app.run(self)
resource_dir = os.path.join(self.dist_dir,
APPNAME + '.app', 'Contents', 'Resources')
@ -249,8 +240,8 @@ _check_symlinks_prescript()
f.close()
os.chmod(path, stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH|stat.S_IREAD\
|stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP)
self.add_qt_plugins()
plugin_files += self.build_plugins()
self.add_plugins()
print
print 'Adding clit'
@ -264,13 +255,8 @@ _check_symlinks_prescript()
print 'Adding plugins'
module_dir = os.path.join(resource_dir, 'lib', 'python2.5', 'lib-dynload')
print 'Adding fontconfig'
for f in glob.glob(os.path.expanduser('~/fontconfig2/*')):
for f in glob.glob(os.path.expanduser('~/fontconfig-bundled/*')):
os.link(f, os.path.join(frameworks_dir, os.path.basename(f)))
for src, dest in plugin_files:
if 'dylib' in dest:
os.link(src, os.path.join(frameworks_dir, dest))
else:
os.link(src, os.path.join(module_dir, dest))
dst = os.path.join(resource_dir, 'fonts')
if os.path.exists(dst):
shutil.rmtree(dst)
@ -281,6 +267,15 @@ _check_symlinks_prescript()
dst = os.path.join(resource_dir, 'lib', 'python2.5', 'IPython')
if os.path.exists(dst): shutil.rmtree(dst)
shutil.copytree(os.path.expanduser('~/build/ipython/IPython'), dst)
print
print 'Adding ImageMagick'
dest = os.path.join(frameworks_dir, 'ImageMagick')
if os.path.exists(dest):
sutil.rmtree(dest)
shutil.copytree(os.path.expanduser('~/ImageMagick'), dest, True)
shutil.copyfile('/usr/local/lib/libpng12.0.dylib', os.path.join(dest, 'lib', 'libpng12.0.dylib'))
print
print 'Installing prescipt'
sf = [os.path.basename(s) for s in all_names]
@ -341,6 +336,8 @@ def main():
'NSHumanReadableCopyright':'Copyright 2008, Kovid Goyal',
'LSEnvironment':{
'FC_CONFIG_DIR':'@executable_path/../Resources/fonts',
'MAGICK_HOME':'@executable_path/../Frameworks/ImageMagick',
'DYLD_LIBRARY_PATH':'@executable_path/../Frameworks/ImageMagick/lib',
}
},
},

View File

@ -240,7 +240,6 @@ File ::B145A772-C20C-A6F2-E872-ACC229FFE1C7 -name fb2-meta.exe -parent 6CCF3F71-
File ::168973D9-DEE6-7307-9A2E-746EB9456311 -name txt2lrf.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::BD39D6F0-5125-F3A3-043F-E8FD1C87A823 -name isbndb.exe -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::6C294A11-52D4-C567-64F7-1DCF21AB06D7 -name epub2lrf.exe -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::BBE8D78B-6646-5327-563C-7F8EE5842D7B -name pictureflow.pyd -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::A9BB9531-5BC4-92C1-F614-B84B93F8698F -name pywintypes25.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::AA725BD8-5FFA-B426-733F-5A1264A30DA2 -name Qt.pyd -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::B48D9BFD-326D-1C92-4D94-C17F9ACD9207 -name epub2lrf.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
@ -264,7 +263,6 @@ File ::2AABAB06-38EF-6F8C-3675-575D8B044E0C -name calibredb.exe -parent 6CCF3F71
File ::A7EA318A-0542-FBB8-5C93-A39B364A51D9 -name epub-meta.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::4CD878C5-1487-1FFD-99A1-EDFC90892F0A -name win32security.pyd -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::ADFDF202-EED8-0319-0D69-DF1C44AE465B -name librarything.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::B522E7CC-3C9B-325B-B0BA-3CAFD0228B6D -name pictureflow0.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::0E83E956-FF8D-27AB-9BE9-A24C57F8886A -name pythoncom25.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::F8DAAE4E-9BF0-F75A-78BD-81E0F4BD1F99 -name epub-meta.exe -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::E2982BD3-D0BB-70B4-0BF8-18B2B68C9918 -name QtWebKit4.dll -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
@ -351,6 +349,12 @@ File ::92701E8F-1D91-A796-C899-2A266029F61D -name _socket.pyd -parent 6CCF3F71-7
File ::45BD27B5-B910-7633-C827-37E82E89C27C -name w9xpopen.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::45C27909-D761-787F-84B2-66596E5C4E99 -name bz2.pyd -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::7B2DE5D8-17A6-B167-ABC7-799AEBCC1C02 -name clit.exe -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::36E8EEAC-F54D-5DE9-02D8-ECDFEBB4B5E2 -type dir -name plugins -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::71930E14-A27B-C23C-8D94-C7E97ADB8723 -name pictureflow.pyd -parent 36E8EEAC-F54D-5DE9-02D8-ECDFEBB4B5E2
File ::293E6ABE-17C9-5E53-1B44-C27029C8C061 -name winutil.pyd -parent 36E8EEAC-F54D-5DE9-02D8-ECDFEBB4B5E2
File ::A5737158-18DF-7F20-2BDF-2DF615663891 -name lzx.pyd -parent 36E8EEAC-F54D-5DE9-02D8-ECDFEBB4B5E2
File ::CA9E098C-2931-9781-1303-213C242F9A5E -name lit2oeb.exe -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
File ::16B5A447-066C-C93E-F63D-8BC0D57CA544 -name lit2oeb.exe.local -parent 6CCF3F71-74BB-ED69-D0E6-9F12348ABDD3
Component ::F6829AB7-9F66-4CEE-CA0E-21F54C6D3609 -setup Install -active Yes -platforms {AIX-ppc FreeBSD-4-x86 FreeBSD-x86 HPUX-hppa Linux-x86 Solaris-sparc Windows} -name Main -parent Components
SetupType ::D9ADE41C-B744-690C-2CED-CF826BF03D2E -setup Install -active Yes -platforms {AIX-ppc FreeBSD-4-x86 FreeBSD-x86 HPUX-hppa Linux-x86 Solaris-sparc Windows} -name Typical -parent SetupTypes

View File

@ -50,58 +50,16 @@ class BuildEXE(py2exe.build_exe.py2exe):
</trustInfo>
</assembly>
'''
def build_distutil_plugins(self):
plugins = [
('lzx', os.path.join('utils', 'lzx')),
]
for name, path in plugins:
print 'Building plugin', name
path = os.path.abspath(os.path.join('src', 'calibre', path))
cwd = os.getcwd()
dd = os.path.join(cwd, self.dist_dir)
os.chdir(path)
try:
if os.path.exists('.build'):
shutil.rmtree('.build')
subprocess.check_call(('python', 'setup.py', 'build', '--build-base', '.build'))
plugin = os.path.abspath(glob.glob('.build\\lib*\\%s.pyd'%name)[0])
shutil.copyfile(plugin, os.path.join(dd, os.path.basename(plugin)))
finally:
os.chdir(cwd)
def build_plugins(self):
cwd = os.getcwd()
dd = os.path.join(cwd, self.dist_dir)
try:
os.chdir(os.path.join('src', 'calibre', 'gui2', 'pictureflow'))
if os.path.exists('.build'):
shutil.rmtree('.build')
os.mkdir('.build')
os.chdir('.build')
subprocess.check_call(['qmake', '../pictureflow.pro'])
subprocess.check_call(['mingw32-make', '-f', 'Makefile.Release'])
shutil.copyfile('release\\pictureflow0.dll', os.path.join(dd, 'pictureflow0.dll'))
os.chdir('..\\PyQt')
if not os.path.exists('.build'):
os.mkdir('.build')
os.chdir('.build')
subprocess.check_call(['python', '..\\configure.py'])
subprocess.check_call(['mingw32-make', '-f', 'Makefile'])
shutil.copyfile('pictureflow.pyd', os.path.join(dd, 'pictureflow.pyd'))
os.chdir('..')
shutil.rmtree('.build', True)
os.chdir('..')
shutil.rmtree('.build', True)
finally:
os.chdir(cwd)
def run(self):
if not os.path.exists(self.dist_dir):
os.makedirs(self.dist_dir)
print 'Building custom plugins...'
self.build_distutil_plugins()
self.build_plugins()
py2exe.build_exe.py2exe.run(self)
print 'Adding plugins...'
tgt = os.path.join(self.dist_dir, 'plugins')
if not os.path.exists(tgt):
os.mkdir(tgt)
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.dll')):
shutil.copyfile(f, os.path.join(self.dist_dir, os.path.basename(f)))
for f in glob.glob(os.path.join(BASE_DIR, 'src', 'calibre', 'plugins', '*.pyd')):
shutil.copyfile(f, os.path.join(tgt, os.path.basename(f)))
qtsvgdll = None
for other in self.other_depends:
if 'qtsvg4.dll' in other.lower():
@ -116,7 +74,7 @@ class BuildEXE(py2exe.build_exe.py2exe):
print 'Adding', qtxmldll
shutil.copyfile(qtxmldll,
os.path.join(self.dist_dir, os.path.basename(qtxmldll)))
print 'Adding plugins...',
print 'Adding Qt plugins...',
qt_prefix = QT_DIR
if qtsvgdll:
qt_prefix = os.path.dirname(os.path.dirname(qtsvgdll))
@ -152,7 +110,8 @@ class BuildEXE(py2exe.build_exe.py2exe):
print '\tAdding pdftohtml'
shutil.copyfile(PDFTOHTML, os.path.join(PY2EXE_DIR, os.path.basename(PDFTOHTML)))
print '\tAdding ImageMagick'
shutil.copytree(IMAGEMAGICK_DIR, os.path.join(PY2EXE_DIR, 'ImageMagick'))
for f in os.listdir(IMAGEMAGICK_DIR):
shutil.copyfile(os.path.join(IMAGEMAGICK_DIR, f), os.path.join(PY2EXE_DIR, f))
print '\tCopying fontconfig'
for f in glob.glob(os.path.join(FONTCONFIG_DIR, '*')):
tgt = os.path.join(PY2EXE_DIR, os.path.basename(f))

View File

@ -4,7 +4,9 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import sys, re, os, shutil
sys.path.append('src')
islinux = not ('win32' in sys.platform or 'win64' in sys.platform or 'darwin' in sys.platform)
iswindows = re.search('win(32|64)', sys.platform)
isosx = 'darwin' in sys.platform
islinux = not isosx and not iswindows
src = open('src/calibre/__init__.py', 'rb').read()
VERSION = re.search(r'__version__\s+=\s+[\'"]([^\'"]+)[\'"]', src).group(1)
APPNAME = re.search(r'__appname__\s+=\s+[\'"]([^\'"]+)[\'"]', src).group(1)
@ -44,10 +46,64 @@ main_functions = {
}
if __name__ == '__main__':
from setuptools import setup, find_packages
from setuptools import setup, find_packages, Extension
import subprocess, glob
entry_points['console_scripts'].append('calibre_postinstall = calibre.linux:post_install')
ext_modules = [Extension('calibre.plugins.lzx',
sources=['src/calibre/utils/lzx/lzxmodule.c',
'src/calibre/utils/lzx/lzxd.c'],
include_dirs=['src/calibre/utils/lzx']),
Extension('calibre.plugins.msdes',
sources=['src/calibre/utils/msdes/msdesmodule.c',
'src/calibre/utils/msdes/des.c'],
include_dirs=['src/calibre/utils/msdes'])]
if iswindows:
ext_modules.append(Extension('calibre.plugins.winutil',
sources=['src/calibre/utils/windows/winutil.c'],
libraries=['shell32', 'setupapi'],
include_dirs=['C:/WinDDK/6001.18001/inc/api/'])
)
if isosx:
ext_modules.append(Extension('calibre.plugins.usbobserver',
sources=['src/calibre/devices/usbobserver/usbobserver.c'])
)
def build_PyQt_extension(path):
pro = glob.glob(os.path.join(path, '*.pro'))[0]
raw = open(pro).read()
base = qtplugin = re.search(r'TARGET\s*=\s*(.*)', raw).group(1)
ver = re.search(r'VERSION\s*=\s*(\d+)', raw).group(1)
cwd = os.getcwd()
os.chdir(os.path.dirname(pro))
try:
if not os.path.exists('.build'):
os.mkdir('.build')
os.chdir('.build')
subprocess.check_call(( (os.path.expanduser('~/qt/bin/qmake') if isosx else 'qmake'), '..'+os.sep+os.path.basename(pro)))
subprocess.check_call(['mingw32-make' if iswindows else 'make'])
os.chdir(os.path.join('..', 'PyQt'))
if not os.path.exists('.build'):
os.mkdir('.build')
os.chdir('.build')
python = '/Library/Frameworks/Python.framework/Versions/Current/bin/python' if isosx else 'python'
subprocess.check_call([python, '..'+os.sep+'configure.py'])
subprocess.check_call(['mingw32-make' if iswindows else 'make'])
ext = '.pyd' if iswindows else '.so'
plugin = glob.glob(base+ext)[0]
shutil.copyfile(plugin, os.path.join(cwd, 'src', 'calibre', 'plugins', plugin))
finally:
os.chdir(cwd)
if islinux or isosx:
for f in glob.glob(os.path.join('src', 'calibre', 'plugins', '*')):
try:
os.readlink(f)
os.unlink(f)
except:
continue
for path in [(os.path.join('src', 'calibre', 'gui2', 'pictureflow'))]:
build_PyQt_extension(path)
setup(
name=APPNAME,
@ -62,6 +118,7 @@ if __name__ == '__main__':
entry_points = entry_points,
zip_safe = False,
options = { 'bdist_egg' : {'exclude_source_files': True,}, },
ext_modules=ext_modules,
description =
'''
E-book management application.

View File

@ -1,7 +1,7 @@
''' E-book management software'''
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
__version__ = '0.4.79'
__version__ = '0.4.80'
__docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid at kovidgoyal.net>"
__appname__ = 'calibre'
@ -20,7 +20,7 @@ from PyQt4.QtGui import QDesktopServices
from calibre.translations.msgfmt import make
from calibre.ebooks.chardet import detect
from calibre.terminfo import TerminalController
from calibre.utils.terminfo import TerminalController
terminal_controller = TerminalController(sys.stdout)
iswindows = 'win32' in sys.platform.lower() or 'win64' in sys.platform.lower()
@ -43,6 +43,41 @@ try:
except:
preferred_encoding = 'utf-8'
if getattr(sys, 'frozen', False):
if iswindows:
plugin_path = os.path.join(os.path.dirname(sys.executable), 'plugins')
elif isosx:
plugin_path = os.path.join(getattr(sys, 'frameworks_dir'), 'plugins')
elif islinux:
plugin_path = os.path.join(getattr(sys, 'frozen_path'), 'plugins')
sys.path.insert(0, plugin_path)
else:
import pkg_resources
plugins = getattr(pkg_resources, 'resource_filename')(__appname__, 'plugins')
sys.path.insert(0, plugins)
if iswindows and getattr(sys, 'frozen', False):
sys.path.insert(1, os.path.dirname(sys.executable))
plugins = {}
for plugin in ['pictureflow', 'lzx', 'msdes'] + \
(['winutil'] if iswindows else []) + \
(['usbobserver'] if isosx else []):
try:
p, err = __import__(plugin), ''
except Exception, err:
p = None
err = str(err)
plugins[plugin] = (p, err)
if iswindows:
winutil, winutilerror = plugins['winutil']
if not winutil:
raise RuntimeError('Failed to load the winutil plugin: %s'%winutilerror)
sys.argv[1:] = winutil.argv()[1:]
_abspath = os.path.abspath
def my_abspath(path, encoding=sys.getfilesystemencoding()):
'''
@ -268,10 +303,10 @@ def filename_to_utf8(name):
def extract(path, dir):
ext = os.path.splitext(path)[1][1:].lower()
extractor = None
if ext == 'zip':
if ext in ['zip', 'cbz', 'epub']:
from calibre.libunzip import extract as zipextract
extractor = zipextract
elif ext == 'rar':
elif ext in ['cbr', 'rar']:
from calibre.libunrar import extract as rarextract
extractor = rarextract
if extractor is None:
@ -605,23 +640,3 @@ if isosx:
for font in fonts:
exec 'from calibre.ebooks.lrf.fonts.liberation.'+font+' import font_data'
open(os.path.join(fdir, font+'.ttf'), 'wb').write(font_data)
if islinux and not getattr(sys, 'frozen', False):
import pkg_resources
plugins = pkg_resources.resource_filename(__appname__, 'plugins')
sys.path.insert(1, plugins)
if iswindows and getattr(sys, 'frozen', False):
sys.path.insert(1, os.path.dirname(sys.executable))
plugins = {}
for plugin in ['pictureflow', 'lzx']:
try:
p, err = __import__(plugin), ''
except Exception, err:
p = None
err = str(err)
plugins[plugin] = (p, err)

View File

@ -23,6 +23,10 @@ Run an embedded python interpreter.
return parser
def update_zipfile(zipfile, mod, path):
if 'win32' in sys.platform:
print 'WARNING: On Windows Vista you must run this from a console that has been started in Administrator mode.'
print 'Press Enter to continue or Ctrl-C to Cancel'
raw_input()
pat = re.compile(mod.replace('.', '/')+r'\.py[co]*')
name = mod.replace('.', '/') + os.path.splitext(path)[-1]
update(zipfile, [pat], [path], [name])

View File

@ -133,31 +133,7 @@ class KINDLE(Device):
def open_windows(self):
drives = []
import wmi
c = wmi.WMI()
for drive in c.Win32_DiskDrive():
'''print drive.PNPDeviceID'''
if self.__class__.is_device(drive.PNPDeviceID):
if drive.Partitions == 0:
continue
try:
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
prefix = logical_disk.DeviceID+os.sep
drives.append((drive.Index, prefix))
except IndexError:
continue
if not drives:
print self.__class__.__name__
raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,))
drives.sort(cmp=lambda a, b: cmp(a[0], b[0]))
self._main_prefix = drives[0][1]
if len(drives) > 1:
self._card_prefix = drives[1][1]
raise NotImplementedError
def open_linux(self):

View File

@ -20,7 +20,8 @@ MIME_MAP = {
'lrx' : 'application/x-sony-bbeb',
"rtf" : "application/rtf",
"pdf" : "application/pdf",
"txt" : "text/plain"
"txt" : "text/plain" ,
'epub': 'application/epub+zip',
}
def uuid():

View File

@ -31,6 +31,7 @@ class PRS505(Device):
PRODUCT_ID = 0x031e #: Product Id for the PRS-505
PRODUCT_NAME = 'PRS-505'
VENDOR_NAME = 'SONY'
FORMATS = ["lrf", 'epub', "rtf", "pdf", "txt"]
MEDIA_XML = 'database/cache/media.xml'
CACHE_XML = 'Sony Reader/database/cache.xml'

View File

@ -7,59 +7,42 @@ manner.
import sys
from calibre import iswindows, isosx
from calibre import iswindows, isosx, plugins
from calibre.devices import libusb
osx_scanner = None
try:
import usbobserver
osx_scanner = usbobserver.get_devices
except ImportError:
pass
osx_scanner = win_scanner = linux_scanner = None
linux_scanner = libusb.get_devices
if iswindows:
try:
win_scanner = plugins['winutil'][0].get_usb_devices
except:
raise RuntimeError('Failed to load the winutil plugin: %s'%plugins['winutil'][1])
elif isosx:
try:
osx_scanner = plugins['usbobserver'][0].get_usb_devices
except:
raise RuntimeError('Failed to load the usbobserver plugin: %s'%plugins['usbobserver'][1])
else:
linux_scanner = libusb.get_devices
class DeviceScanner(object):
def __init__(self, wmi=None):
self.wmi = wmi
if iswindows and wmi is None:
raise RuntimeError('You must pass a wmi instance to DeviceScanner on windows.')
def __init__(self, *args):
if isosx and osx_scanner is None:
raise RuntimeError('The Python extension usbobserver must be available on OS X.')
if not (isosx or iswindows) and not libusb.has_library():
raise RuntimeError('DeviceScanner requires libusb to work.')
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
self.devices = []
def get_devices(self):
if iswindows:
devices = []
for c in self.wmi.USBControllerDevice():
devices.append(c.Dependent.DeviceID.upper())
return devices
if isosx:
return osx_scanner()
return linux_scanner()
def scan(self):
try: # Windows WMI occasionally and temporarily barfs
self.devices = self.get_devices()
except Exception, e:
if not iswindows and e:
raise e
'''Fetch list of connected USB devices from operating system'''
self.devices = self.scanner()
def is_device_connected(self, device):
if iswindows:
for device_id in self.devices:
if 'VEN_'+device.VENDOR_NAME in device_id and \
'PROD_'+device.PRODUCT_NAME in device_id:
return True
vid, pid = hex(device.VENDOR_ID)[2:], hex(device.PRODUCT_ID)[2:]
if len(vid) < 4: vid = '0'+vid
if len(pid) < 4: pid = '0'+pid
vid, pid = 'VID_'+vid.upper(), 'PID_'+pid.upper()
vid, pid = 'vid_%4.4x'%device.VENDOR_ID, 'pid_%4.4x'%device.PRODUCT_ID
if vid in device_id and pid in device_id:
return True
return False

View File

@ -29,7 +29,7 @@
static PyObject *
usbobserver_get_devices(PyObject *self, PyObject *args) {
usbobserver_get_usb_devices(PyObject *self, PyObject *args) {
mach_port_t masterPort;
CFMutableDictionaryRef matchingDict;
@ -62,7 +62,7 @@ usbobserver_get_devices(PyObject *self, PyObject *args) {
PyObject *devices, *device;
devices = PyList_New(0);
if (devices == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Out of memory allocating list");
PyErr_NoMemory();
mach_port_deallocate(mach_task_self(), masterPort);
return NULL;
}
@ -112,7 +112,7 @@ usbobserver_get_devices(PyObject *self, PyObject *args) {
}
static PyMethodDef usbobserver_methods[] = {
{"get_devices", usbobserver_get_devices, METH_VARARGS,
{"get_usb_devices", usbobserver_get_usb_devices, METH_VARARGS,
"Get list of connected USB devices. Returns a list of tuples. Each tuple is of the form (vendor_id, product_id)."
},
{NULL, NULL, 0, NULL}

View File

@ -1,489 +0,0 @@
# Re-modified for use in MS LIT decryption. Un-reversed the bytebit[] array.
# Substituted Microsoft's absurd modified S-boxes. Modified the
# encrypt/decrypt methods to handle more than one block at a time. Added a few
# speed-ups supported by modern versions of Python. Added option 'psyco' use.
#
# And lo, all the previous notices follow:
# Modified DES encryption for VNC password authentication.
# Ported from realvnc's java viewer by <cliechti@gmx.net>
# I chose this package name because it is not compatible with the
# original DES algorithm, e.g. found pycrypto.
#
# (C) 2003 chris <cliechti@gmx.net>
# Released as free software under the Python License.
#
# You're free to use it for commercial and noncommercial
# application, modify and redistribute it as long as the
# copyright notices are intact. There are no warranties, not
# even that it does what it says to do ;-)
#
# Original notice following:
# This DES class has been extracted from package Acme.Crypto for use in VNC.
# The bytebit[] array has been reversed so that the most significant bit
# in each byte of the key is ignored, not the least significant. Also the
# unnecessary odd parity code has been removed.
#
# These changes are:
# Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# DesCipher - the DES encryption method
#
# The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is:
#
# Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
#
# Permission to use, copy, modify, and distribute this software
# and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
# without fee is hereby granted, provided that this copyright notice is kept
# intact.
#
# WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
# OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
# TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
# FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
# DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
#
# THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
# CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
# PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
# NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
# SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
# SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
# PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). WIDGET WORKSHOP
# SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
# HIGH RISK ACTIVITIES.
#
#
# The rest is:
#
# Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# Visit the ACME Labs Java page for up-to-date versions of this and other
# fine Java utilities: http://www.acme.com/java/
#/ The DES encryption method.
# <P>
# This is surprisingly fast, for pure Java. On a SPARC 20, wrapped
# in Acme.Crypto.EncryptedOutputStream or Acme.Crypto.EncryptedInputStream,
# it does around 7000 bytes/second.
# <P>
# Most of this code is by Dave Zimmerman <dzimm@widget.com>, and is
# Copyright (c) 1996 Widget Workshop, Inc. See the source file for details.
# <P>
# <A HREF="/resources/classes/Acme/Crypto/DesCipher.java">Fetch the software.</A><BR>
# <A HREF="/resources/classes/Acme.tar.Z">Fetch the entire Acme package.</A>
# <P>
# @see Des3Cipher
# @see EncryptedOutputStream
# @see EncryptedInputStream
import struct
class DesCipher:
# Constructor, byte-array key.
def __init__(self, key):
self.setKey(key)
#/ Set the key.
def setKey(self, key):
self.encryptKeys = self.deskey([ord(x) for x in key], 1)
self.decryptKeys = self.deskey([ord(x) for x in key], 0)
# Turn an 8-byte key into internal keys.
def deskey(self, keyBlock, encrypting):
#~ int i, j, l, m, n;
pc1m = [0]*56 #new int[56];
pcr = [0]*56 #new int[56];
kn = [0]*32 #new int[32];
for j in xrange(56):
l = pc1[j]
m = l & 07
pc1m[j] = ((keyBlock[l >> 3] & bytebit[m]) != 0)
for i in xrange(16):
if encrypting:
m = i << 1
else:
m = (15-i) << 1
n = m + 1
kn[m] = kn[n] = 0
for j in xrange(28):
l = j + totrot[i]
if l < 28:
pcr[j] = pc1m[l]
else:
pcr[j] = pc1m[l - 28]
for j in xrange(28, 56):
l = j + totrot[i]
if l < 56:
pcr[j] = pc1m[l]
else:
pcr[j] = pc1m[l - 28]
for j in xrange(24):
if pcr[pc2[j]] != 0:
kn[m] |= bigbyte[j]
if pcr[pc2[j+24]] != 0:
kn[n] |= bigbyte[j]
return self.cookey(kn)
def cookey(self, raw):
#~ int raw0, raw1;
#~ int rawi, KnLi;
#~ int i;
KnL = [0]*32
rawi = 0
KnLi = 0
for i in xrange(16):
raw0 = raw[rawi]
rawi += 1
raw1 = raw[rawi]
rawi += 1
KnL[KnLi] = (raw0 & 0x00fc0000L) << 6
KnL[KnLi] |= (raw0 & 0x00000fc0L) << 10
KnL[KnLi] |= (raw1 & 0x00fc0000L) >> 10
KnL[KnLi] |= (raw1 & 0x00000fc0L) >> 6
KnLi += 1
KnL[KnLi] = (raw0 & 0x0003f000L) << 12
KnL[KnLi] |= (raw0 & 0x0000003fL) << 16
KnL[KnLi] |= (raw1 & 0x0003f000L) >> 4
KnL[KnLi] |= (raw1 & 0x0000003fL)
KnLi += 1
return KnL
# Block encryption routines.
#/ Encrypt a block of eight bytes.
def encrypt(self, clearText):
if len(clearText) % 8 != 0:
raise TypeError, "length must be multiple of block size"
result = []
for base in xrange(0, len(clearText), 8):
result.append(struct.pack(
">LL", *self.des(struct.unpack(">LL", clearText[base:base+8]),
self.encryptKeys)))
return ''.join(result)
#/ Decrypt a block of eight bytes.
def decrypt(self, cipherText):
if len(cipherText) % 8 != 0:
raise TypeError, "length must be multiple of block size"
result = []
for base in xrange(0, len(cipherText), 8):
result.append(struct.pack(
">LL", *self.des(struct.unpack(">LL", cipherText[base:base+8]),
self.decryptKeys)))
return ''.join(result)
# The DES function.
def des(self, (leftt, right), keys):
#~ int fval, work, right, leftt;
#~ int round
keysi = 0
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL
right ^= work
leftt ^= (work << 4) & 0xffffffffL
work = ((leftt >> 16) ^ right) & 0x0000ffffL
right ^= work
leftt ^= (work << 16) & 0xffffffffL
work = ((right >> 2) ^ leftt) & 0x33333333L
leftt ^= work
right ^= (work << 2) & 0xffffffffL
work = ((right >> 8) ^ leftt) & 0x00ff00ffL
leftt ^= work
right ^= (work << 8) & 0xffffffffL
right = ((right << 1) | ((right >> 31) & 1)) & 0xffffffffL
work = (leftt ^ right) & 0xaaaaaaaaL
leftt ^= work
right ^= work
leftt = ((leftt << 1) | ((leftt >> 31) & 1)) & 0xffffffffL
for round in xrange(8):
work = ((right << 28) | (right >> 4)) & 0xffffffffL
work ^= keys[keysi]
keysi += 1
fval = SP7[ work & 0x0000003fL ]
fval |= SP5[(work >> 8) & 0x0000003fL ]
fval |= SP3[(work >> 16) & 0x0000003fL ]
fval |= SP1[(work >> 24) & 0x0000003fL ]
work = right ^ keys[keysi]
keysi += 1
fval |= SP8[ work & 0x0000003fL ]
fval |= SP6[(work >> 8) & 0x0000003fL ]
fval |= SP4[(work >> 16) & 0x0000003fL ]
fval |= SP2[(work >> 24) & 0x0000003fL ]
leftt ^= fval
work = ((leftt << 28) | (leftt >> 4)) & 0xffffffffL
work ^= keys[keysi]
keysi += 1
fval = SP7[ work & 0x0000003fL ]
fval |= SP5[(work >> 8) & 0x0000003fL ]
fval |= SP3[(work >> 16) & 0x0000003fL ]
fval |= SP1[(work >> 24) & 0x0000003fL ]
work = leftt ^ keys[keysi]
keysi += 1
fval |= SP8[ work & 0x0000003fL ]
fval |= SP6[(work >> 8) & 0x0000003fL ]
fval |= SP4[(work >> 16) & 0x0000003fL ]
fval |= SP2[(work >> 24) & 0x0000003fL ]
right ^= fval
right = ((right << 31) | (right >> 1)) & 0xffffffffL
work = (leftt ^ right) & 0xaaaaaaaaL
leftt ^= work
right ^= work
leftt = ((leftt << 31) | (leftt >> 1)) & 0xffffffffL
work = ((leftt >> 8) ^ right) & 0x00ff00ffL
right ^= work
leftt ^= (work << 8) & 0xffffffffL
work = ((leftt >> 2) ^ right) & 0x33333333L
right ^= work
leftt ^= (work << 2) & 0xffffffffL
work = ((right >> 16) ^ leftt) & 0x0000ffffL
leftt ^= work
right ^= (work << 16) & 0xffffffffL
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL
leftt ^= work
right ^= (work << 4) & 0xffffffffL
return right, leftt
# Tables, permutations, S-boxes, etc.
bytebit = [0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]
bigbyte = [
0x800000, 0x400000, 0x200000, 0x100000,
0x080000, 0x040000, 0x020000, 0x010000,
0x008000, 0x004000, 0x002000, 0x001000,
0x000800, 0x000400, 0x000200, 0x000100,
0x000080, 0x000040, 0x000020, 0x000010,
0x000008, 0x000004, 0x000002, 0x000001
]
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
]
totrot = [
1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
]
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,
]
# Microsoft's modified S-boxes for LIT file encryption
SP1 = [
0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L,
0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L,
0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L,
0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L,
0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L,
0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L,
0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L,
0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L,
0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L,
0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L,
0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L,
0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L,
0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L
]
SP2 = [
0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L,
0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L,
0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L,
0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L,
0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L,
0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L,
0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L,
0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L,
0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L,
0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L,
0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L,
0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L,
0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L
]
SP3 = [
0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L,
0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L,
0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L,
0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L,
0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L,
0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L,
0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L,
0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L,
0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L,
0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L,
0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L,
0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L,
0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L
]
SP4 = [
0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L,
0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L,
0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L,
0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L,
0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L,
0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L,
0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L,
0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L,
0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L,
0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L,
0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L,
0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L,
0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L
]
SP5 = [
0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L,
0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L,
0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L,
0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L,
0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L,
0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L,
0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L,
0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L,
0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L,
0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L,
0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L,
0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L,
0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L
]
SP6 = [
0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L,
0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L,
0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L,
0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L,
0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L,
0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L,
0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L,
0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L,
0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L,
0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L,
0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L,
0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L,
0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L,
]
SP7 = [
0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L,
0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L,
0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L,
0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L,
0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L,
0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L,
0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L,
0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L,
0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L,
0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L,
0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L,
0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L,
0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L,
]
SP8 = [
0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L,
0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L,
0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L,
0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L,
0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L,
0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L,
0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L,
0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L,
0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L,
0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L,
0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L,
0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L,
0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
]
def new(key):
return DesCipher(key)
block_size = 8
key_size = 8
try:
import psyco
psyco.bind(DesCipher.deskey)
psyco.bind(DesCipher.cookey)
psyco.bind(DesCipher.des)
except ImportError:
pass
#test only:
if __name__ == '__main__':
des = DesCipher("\x01\x23\x45\x67\x89\xab\xcd\xef")
print ''.join(
"%02x" % ord(x) for x in des.encrypt("Now is t"))

View File

@ -9,12 +9,13 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net> ' \
import sys, struct, cStringIO, os
import functools
import re
from calibre.ebooks.lit import LitError
from calibre.ebooks.lit.maps import OPF_MAP, HTML_MAP
import calibre.ebooks.lit.mssha1 as mssha1
import calibre.ebooks.lit.msdes as msdes
from calibre import plugins
lzx, lxzerror = plugins['lzx']
msdes, msdeserror = plugins['msdes']
OPF_DECL = """<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE package
@ -84,7 +85,7 @@ def read_utf8_char(bytes, pos):
if elsize + pos > len(bytes):
raise LitError('Invalid UTF8 character: %s' % repr(bytes[pos]))
c &= (mask - 1)
for i in range(1, elsize):
for i in xrange(1, elsize):
b = ord(bytes[pos+i])
if (b & 0xC0) != 0x80:
raise LitError(
@ -92,34 +93,32 @@ def read_utf8_char(bytes, pos):
c = (c << 6) | (b & 0x3F)
return unichr(c), pos+elsize
def consume_sized_utf8_string(bytes, zpad=False):
result = []
slen, pos = read_utf8_char(bytes, 0)
for i in xrange(ord(slen)):
char, pos = read_utf8_char(bytes, pos)
result.append(char)
if zpad and bytes[pos] == '\000':
pos += 1
return u''.join(result), bytes[pos:]
class UnBinary(object):
AMPERSAND_RE = re.compile(
r'&(?!(?:#[0-9]+|#x[0-9a-fA-F]+|[a-zA-Z_:][a-zA-Z0-9.-_:]+);)')
def __init__(self, bin, manifest, map=OPF_MAP):
self.manifest = manifest
self.tag_map, self.attr_map, self.tag_to_attr_map = map
self.opf = map is OPF_MAP
self.bin = bin
self.buf = cStringIO.StringIO()
self.ampersands = []
self.binary_to_text()
self.raw = self.buf.getvalue().lstrip().decode('utf-8')
self.escape_ampersands()
def escape_ampersands(self):
offset = 0
for pos in self.ampersands:
test = self.raw[pos+offset:pos+offset+6]
if test.startswith('&#') and ';' in test:
continue
escape = True
for ent in XML_ENTITIES:
if test.startswith(ent):
escape = False
break
if not escape:
continue
self.raw = '&amp;'.join(
(self.raw[:pos+offset], self.raw[pos+offset+1:]))
offset += 4
self.raw = self.AMPERSAND_RE.sub('&amp;', self.raw)
def item_path(self, internal_id):
try:
@ -148,8 +147,6 @@ class UnBinary(object):
continue
elif c == '\v':
c = '\n'
elif c == '&':
self.ampersands.append(self.buf.tell()-1)
self.buf.write(c.encode('utf-8'))
elif state == 'get flags':
@ -328,8 +325,11 @@ class ManifestItem(object):
self.offset = offset
self.root = root
self.state = state
# Some LIT files have Windows-style paths
path = original.replace('\\', '/')
if path[1:3] == ':/': path = path[2:]
# Some paths in Fictionwise "multiformat" LIT files contain '..' (!?)
path = os.path.normpath(original).replace('\\', '/')
path = os.path.normpath(path).replace('\\', '/')
while path.startswith('../'): path = path[3:]
self.path = path
@ -475,7 +475,7 @@ class LitReader(object):
def _read_header_pieces(self):
src = self.header[self.hdr_len:]
for i in range(self.num_pieces):
for i in xrange(self.num_pieces):
piece = src[i * self.PIECE_SIZE:(i + 1) * self.PIECE_SIZE]
if u32(piece[4:]) != 0 or u32(piece[12:]) != 0:
raise LitError('Piece %s has 64bit value' % repr(piece))
@ -525,7 +525,7 @@ class LitReader(object):
raise LitError('Directory entry had 64bit name length.')
if namelen > remaining - 3:
raise LitError('Read past end of directory chunk')
name, chunk = chunk[:namelen], chunk[namelen:]
name, chunk = chunk[:namelen].decode('utf-8'), chunk[namelen:]
section, chunk, remaining = encint(chunk, remaining)
offset, chunk, remaining = encint(chunk, remaining)
size, chunk, remaining = encint(chunk, remaining)
@ -542,7 +542,7 @@ class LitReader(object):
self.num_sections = u16(raw[2:pos])
self.section_names = [""]*self.num_sections
self.section_data = [None]*self.num_sections
for section in range(self.num_sections):
for section in xrange(self.num_sections):
size = u16(raw[pos:pos+2])
pos += 2
size = size*2 + 2
@ -570,27 +570,31 @@ class LitReader(object):
if len(raw) < 5:
raise LitError('Truncated manifest')
offset, raw = u32(raw), raw[4:]
slen, raw = ord(raw[0]), raw[1:]
internal, raw = raw[:slen].decode('utf8'), raw[slen:]
slen, raw = ord(raw[0]), raw[1:]
original, raw = raw[:slen].decode('utf8'), raw[slen:]
slen, raw = ord(raw[0]), raw[1:]
mime_type, raw = raw[:slen].decode('utf8'), raw[slen+1:]
internal, raw = consume_sized_utf8_string(raw)
original, raw = consume_sized_utf8_string(raw)
# Is this last one UTF-8 or ASCIIZ?
mime_type, raw = consume_sized_utf8_string(raw, zpad=True)
self.manifest[internal] = ManifestItem(
original, internal, mime_type, offset, root, state)
mlist = self.manifest.values()
shared = mlist[0].path
for item in mlist[1:]:
path = item.path
while shared and not path.startswith(shared):
try: shared = shared[:shared.rindex("/", 0, -2) + 1]
except ValueError: shared = None
if not shared:
break
if shared:
slen = len(shared)
for item in mlist:
item.path = item.path[slen:]
# Remove any common path elements
if len(mlist) > 1:
shared = mlist[0].path
for item in mlist[1:]:
path = item.path
while shared and not path.startswith(shared):
try: shared = shared[:shared.rindex("/", 0, -2) + 1]
except ValueError: shared = None
if not shared:
break
if shared:
slen = len(shared)
for item in mlist:
item.path = item.path[slen:]
# Fix any straggling absolute paths
for item in mlist:
if item.path[0] == '/':
item.path = os.path.basename(item.path)
def _read_meta(self):
raw = self.get_file('/meta')
@ -614,8 +618,8 @@ class LitReader(object):
self.drmlevel = 1
else:
return
des = msdes.new(self._calculate_deskey())
bookkey = des.decrypt(self.get_file('/DRMStorage/DRMSealed'))
msdes.deskey(self._calculate_deskey(), msdes.DE1)
bookkey = msdes.des(self.get_file('/DRMStorage/DRMSealed'))
if bookkey[0] != '\000':
raise LitError('Unable to decrypt title key!')
self.bookkey = bookkey[1:9]
@ -690,7 +694,8 @@ class LitReader(object):
def _decrypt(self, content):
if self.drmlevel == 5:
raise LitError('Cannot extract content from a DRM protected ebook')
return msdes.new(self.bookkey).decrypt(content)
msdes.deskey(self.bookkey, msdes.DE1)
return msdes.des(content)
def _decompress(self, content, control, reset_table):
if len(control) < 32 or control[CONTROL_TAG:CONTROL_TAG+4] != "LZXC":
@ -792,5 +797,12 @@ def main(args=sys.argv):
print _('OEB ebook created in'), opts.output_dir
return 0
try:
import psyco
psyco.bind(read_utf8_char)
psyco.bind(UnBinary.binary_to_text)
except ImportError:
pass
if __name__ == '__main__':
sys.exit(main())

View File

@ -0,0 +1,16 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
'''
Convert CBR/CBZ files to LRF.
'''
import sys
def main(args=sys.argv):
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@ -0,0 +1,321 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
'''
Based on ideas from comiclrf created by FangornUK.
'''
import os, sys, traceback, shutil
from uuid import uuid4
from calibre import extract, OptionParser, detect_ncpus, terminal_controller, \
__appname__, __version__
from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.utils.threadpool import ThreadPool, WorkRequest
from calibre.utils.terminfo import ProgressBar
from calibre.ebooks.lrf.pylrs.pylrs import Book, BookSetting, ImageStream, ImageBlock
try:
from calibre.utils.PythonMagickWand import \
NewMagickWand, NewPixelWand, \
MagickSetImageBorderColor, \
MagickReadImage, MagickRotateImage, \
MagickTrimImage, \
MagickNormalizeImage, MagickGetImageWidth, \
MagickGetImageHeight, \
MagickResizeImage, MagickSetImageType, \
GrayscaleType, CatromFilter, MagickSetImagePage, \
MagickBorderImage, MagickSharpenImage, \
MagickQuantizeImage, RGBColorspace, \
MagickWriteImage, DestroyPixelWand, \
DestroyMagickWand, CloneMagickWand, \
MagickThumbnailImage, MagickCropImage, initialize, finalize
_imagemagick_loaded = True
except:
_imagemagick_loaded = False
PROFILES = {
'prs500':(584, 754),
}
def extract_comic(path_to_comic_file):
'''
Un-archive the comic file.
'''
tdir = PersistentTemporaryDirectory(suffix='comic_extract')
extract(path_to_comic_file, tdir)
return tdir
def find_pages(dir, sort_on_mtime=False, verbose=False):
'''
Find valid comic pages in a previously un-archived comic.
:param dir: Directory in which extracted comic lives
:param sort_on_mtime: If True sort pages based on their last modified time.
Otherwise, sort alphabetically.
'''
extensions = ['jpeg', 'jpg', 'gif', 'png']
pages = []
for datum in os.walk(dir):
for name in datum[-1]:
path = os.path.join(datum[0], name)
for ext in extensions:
if path.lower().endswith('.'+ext):
pages.append(path)
break
if sort_on_mtime:
comparator = lambda x, y : cmp(os.stat(x).st_mtime, os.stat(y).st_mtime)
else:
comparator = lambda x, y : cmp(os.path.basename(x), os.path.basename(y))
pages.sort(cmp=comparator)
if verbose:
print 'Found comic pages...'
print '\t'+'\n\t'.join([os.path.basename(p) for p in pages])
return pages
class PageProcessor(list):
'''
Contains the actual image rendering logic. See :method:`__call__` and
:method:`process_pages`.
'''
def __init__(self, path_to_page, dest, opts, num):
self.path_to_page = path_to_page
self.opts = opts
self.num = num
self.dest = dest
self.rotate = False
list.__init__(self)
def __call__(self):
try:
img = NewMagickWand()
if img < 0:
raise RuntimeError('Cannot create wand.')
if not MagickReadImage(img, self.path_to_page):
raise IOError('Failed to read image from: %'%self.path_to_page)
width = MagickGetImageWidth(img)
height = MagickGetImageHeight(img)
if self.num == 0: # First image so create a thumbnail from it
thumb = CloneMagickWand(img)
if thumb < 0:
raise RuntimeError('Cannot create wand.')
MagickThumbnailImage(thumb, 60, 80)
MagickWriteImage(thumb, os.path.join(self.dest, 'thumbnail.png'))
DestroyMagickWand(thumb)
self.pages = [img]
if width > height:
if self.opts.landscape:
self.rotate = True
else:
split1, split2 = map(CloneMagickWand, (img, img))
if split1 < 0 or split2 < 0:
raise RuntimeError('Cannot create wand.')
DestroyMagickWand(img)
MagickCropImage(split1, (width/2)-1, height, 0, 0)
MagickCropImage(split2, (width/2)-1, height, width/2, 0 )
self.pages = [split1, split2]
self.process_pages()
except Exception, err:
print 'Failed to process page: %s'%os.path.basename(self.path_to_page)
print 'Error:', err
if self.opts.verbose:
traceback.print_exc()
def process_pages(self):
for i, wand in enumerate(self.pages):
pw = NewPixelWand()
if pw < 0:
raise RuntimeError('Cannot create wand.')
#flag = PixelSetColor(pw, 'white')
MagickSetImageBorderColor(wand, pw)
if self.rotate:
MagickRotateImage(wand, pw, -90)
# 25 percent fuzzy trim?
MagickTrimImage(wand, 25*65535/100)
MagickSetImagePage(wand, 0,0,0,0) #Clear page after trim, like a "+repage"
# Do the Photoshop "Auto Levels" equivalent
if self.opts.normalize:
MagickNormalizeImage(wand)
sizex = MagickGetImageWidth(wand)
sizey = MagickGetImageHeight(wand)
SCRWIDTH, SCRHEIGHT = PROFILES[self.opts.profile]
if self.opts.keep_aspect_ratio:
# Preserve the aspect ratio by adding border
aspect = float(sizex) / float(sizey)
if aspect <= (float(SCRWIDTH) / float(SCRHEIGHT)):
newsizey = SCRHEIGHT
newsizex = int(newsizey * aspect)
deltax = (SCRWIDTH - newsizex) / 2
deltay = 0
else:
newsizex = SCRWIDTH
newsizey = int(newsizex / aspect)
deltax = 0
deltay = (SCRHEIGHT - newsizey) / 2
MagickResizeImage(wand, newsizex, newsizey, CatromFilter, 1.0)
MagickSetImageBorderColor(wand, pw)
MagickBorderImage(wand, pw, deltax, deltay)
else:
MagickResizeImage(wand, SCRWIDTH, SCRHEIGHT, CatromFilter, 1.0)
if self.opts.sharpen:
MagickSharpenImage(wand, 0.0, 1.0)
MagickSetImageType(wand, GrayscaleType)
MagickQuantizeImage(wand, self.opts.colors, RGBColorspace, 0, 1, 0)
dest = '%d_%d%s'%(self.num, i, os.path.splitext(self.path_to_page)[-1])
dest = os.path.join(self.dest, dest)
MagickWriteImage(wand, dest)
self.append(dest)
DestroyPixelWand(pw)
wand = DestroyMagickWand(wand)
class Progress(object):
def __init__(self, total, update):
self.total = total
self.update = update
self.done = 0
def __call__(self, req, res):
self.done += 1
self.update(float(self.done)/self.total,
_('Rendered %s')%os.path.basename(req.callable.path_to_page))
def process_pages(pages, opts, update):
'''
Render all identified comic pages.
'''
if not _imagemagick_loaded:
raise RuntimeError('Failed to load ImageMagick')
initialize()
try:
tdir = PersistentTemporaryDirectory('_comic2lrf_pp')
processed_pages = [PageProcessor(path, tdir, opts, i) for i, path in enumerate(pages)]
tp = ThreadPool(detect_ncpus())
update(0, '')
notify = Progress(len(pages), update)
for pp in processed_pages:
tp.putRequest(WorkRequest(pp, callback=notify))
tp.wait()
ans, failures = [], []
for pp in processed_pages:
if len(pp) == 0:
failures.append(os.path.basename(pp.path_to_page()))
else:
ans += pp
return ans, failures, tdir
finally:
finalize()
def option_parser():
parser = OptionParser(_('''\
%prog [options] comic.cb[z|r]
Convert a comic in a CBZ or CBR file to an LRF ebook.
'''))
parser.add_option('-t', '--title', help=_('Title for generated ebook. Default is to use the filename.'), default=None)
parser.add_option('-a', '--author', help=_('Set the author in the metadata of the generated ebook. Default is %default'), default=_('Unknown'))
parser.add_option('-o', '--output', help=_('Path to output LRF file. By default a file is created in the current directory.'), default=None)
parser.add_option('-c', '--colors', type='int', default=64,
help=_('Number of colors for Grayscale image conversion. Default: %default'))
parser.add_option('-n', '--disable-normalize', dest='normalize', default=True, action='store_false',
help=_('Disable normalize (improve contrast) color range for pictures. Default: False'))
parser.add_option('-r', '--keep-aspect-ratio', action='store_true', default=False,
help=_('Maintain picture aspect ratio. Default is to fill the screen.'))
parser.add_option('-s', '--disable-sharpen', default=True, action='store_false', dest='sharpen',
help=_('Disable sharpening.'))
parser.add_option('-l', '--landscape', default=False, action='store_true',
help=_("Don't split landscape images into two portrait images"))
parser.add_option('--no-sort', default=False, action='store_true',
help=_("Don't sort the files found in the comic alphabetically by name. Instead use the order they were added to the comic."))
parser.add_option('-p', '--profile', default='prs500', dest='profile', type='choice',
choices=PROFILES.keys(), help=_('Choose a profile for the device you are generating this LRF for. The default is the SONY PRS-500 with a screen size of 584x754 pixels. Choices are %s')%PROFILES.keys())
parser.add_option('--verbose', default=False, action='store_true',
help=_('Be verbose, useful for debugging'))
parser.add_option('--no-progress-bar', default=False, action='store_true',
help=_("Don't show progress bar."))
return parser
def create_lrf(pages, profile, opts, thumbnail=None):
width, height = PROFILES[profile]
ps = {}
ps['topmargin'] = 0
ps['evensidemargin'] = 0
ps['oddsidemargin'] = 0
ps['textwidth'] = width
ps['textheight'] = height
book = Book(title=opts.title, author=opts.author,
bookid=uuid4().hex,
publisher='%s %s'%(__appname__, __version__), thumbnail=thumbnail,
category='Comic', pagestyledefault=ps,
booksetting=BookSetting(screenwidth=width, screenheight=height))
for page in pages:
imageStream = ImageStream(page)
_page = book.create_page()
_page.append(ImageBlock(refstream=imageStream,
blockwidth=width, blockheight=height, xsize=width,
ysize=height, x1=width, y1=height))
book.append(_page)
book.renderLrf(open(opts.output, 'wb'))
def main(args=sys.argv, notification=None):
parser = option_parser()
opts, args = parser.parse_args(args)
if len(args) < 2:
parser.print_help()
print '\nYou must specify a file to convert'
return 1
if not callable(notification):
pb = ProgressBar(terminal_controller, _('Rendering comic pages...'),
no_progress_bar=opts.no_progress_bar)
notification = pb.update
source = os.path.abspath(args[1])
if not opts.title:
opts.title = os.path.splitext(os.path.basename(source))
if not opts.output:
opts.output = os.path.abspath(os.path.splitext(os.path.basename(source))[0]+'.lrf')
tdir = extract_comic(source)
pages = find_pages(tdir, sort_on_mtime=opts.no_sort, verbose=opts.verbose)
if not pages:
raise ValueError('Could not find any pages in the comic: %s'%source)
pages, failures, tdir2 = process_pages(pages, opts, notification)
if not pages:
raise ValueError('Could not find any valid pages in the comic: %s'%source)
if failures:
print 'Could not process the following pages (run with --verbose to see why):'
for f in failures:
print '\t', f
thumbnail = os.path.join(tdir2, 'thumbnail.png')
if not os.access(thumbnail, os.R_OK):
thumbnail = None
create_lrf(pages, opts.profile, opts, thumbnail=thumbnail)
shutil.rmtree(tdir)
shutil.rmtree(tdir2)
return 0
if __name__ == '__main__':
sys.exit(main())

View File

@ -1327,7 +1327,7 @@ class HTMLConverter(object, LoggingInterface):
bls, ls = int(self.book.defaultTextStyle.attrs['baselineskip']), \
int(self.book.defaultTextStyle.attrs['linespace'])
try: # See if line-height is a unitless number
val = int(float(tag_css['line-height'].strip()) * (bls+ls))
val = int(float(tag_css['line-height'].strip()) * (ls))
fp['linespace'] = val
except ValueError:
val = self.unit_convert(tag_css['line-height'], pts=True, base_length='1pt')
@ -1519,7 +1519,8 @@ class HTMLConverter(object, LoggingInterface):
css, pcss = self.parse_css(text)
ncss.update(css)
npcss.update(pcss)
elif tag.has_key('type') and tag['type'] == "text/css" \
elif tag.has_key('type') \
and tag['type'] in ("text/css", "text/x-oeb1-css") \
and tag.has_key('href'):
path = munge_paths(self.target_prefix, tag['href'])[0]
try:

View File

@ -5,10 +5,11 @@ import os, sys, shutil, glob, logging
from tempfile import mkdtemp
from subprocess import Popen, PIPE
from calibre.ebooks.lrf import option_parser as lrf_option_parser
from calibre.ebooks.lit.reader import LitReader
from calibre.ebooks import ConversionError
from calibre.ebooks.lrf.html.convert_from import process_file as html_process_file
from calibre.ebooks.metadata.opf import OPFReader
from calibre import isosx, __appname__, setup_cli_handlers, iswindows, islinux
from calibre import isosx, __appname__, setup_cli_handlers, islinux
CLIT = 'clit'
if isosx and hasattr(sys, 'frameworks_dir'):
@ -17,22 +18,33 @@ if islinux and getattr(sys, 'frozen_path', False):
CLIT = os.path.join(getattr(sys, 'frozen_path'), 'clit')
def option_parser():
return lrf_option_parser(
parser = lrf_option_parser(
_('''Usage: %prog [options] mybook.lit
%prog converts mybook.lit to mybook.lrf''')
)
parser.add_option('--lit2oeb', default=False, dest='lit2oeb', action='store_true',
help='Use the new lit2oeb to convert lit files instead of convertlit.')
return parser
def generate_html2(pathtolit, logger):
if not os.access(pathtolit, os.R_OK):
raise ConversionError, 'Cannot read from ' + pathtolit
tdir = mkdtemp(prefix=__appname__+'_')
lr = LitReader(pathtolit)
print 'Extracting LIT file to', tdir
lr.extract_content(tdir)
return tdir
def generate_html(pathtolit, logger):
if not os.access(pathtolit, os.R_OK):
raise ConversionError, 'Cannot read from ' + pathtolit
tdir = mkdtemp(prefix=__appname__+'_')
os.rmdir(tdir)
sep = r'\\' if iswindows else os.path.sep
cmd = ' '.join([CLIT, '"'+pathtolit+'"', '"%s"'%(tdir+sep,)])
logger.debug(cmd)
p = Popen(cmd, shell=True, stderr=PIPE, stdout=PIPE)
cmd = [CLIT, pathtolit, '%s'%(tdir+os.sep)]
logger.debug(repr(cmd))
p = Popen(cmd, stderr=PIPE, stdout=PIPE)
stdout = p.stdout.read()
err = p.stderr.read()
logger.info(p.stdout.read())
@ -51,7 +63,8 @@ def process_file(path, options, logger=None):
logger = logging.getLogger('lit2lrf')
setup_cli_handlers(logger, level)
lit = os.path.abspath(os.path.expanduser(path))
tdir = generate_html(lit, logger)
tdir = generate_html2(lit, logger) if getattr(options, 'lit2oeb', False) \
else generate_html(lit, logger)
try:
opf = glob.glob(os.path.join(tdir, '*.opf'))
if opf:

View File

@ -744,10 +744,9 @@ class Text(LRFStream):
self.content.append(self.__class__.TextTag(name))
def empline(self, tag, stream):
def invalid(op):
stream.seek(op)
self.simple_container(None, 'EmpLine')
#self.simple_container(None, 'EmpLine')
oldpos = stream.tell()
try:
@ -770,7 +769,8 @@ class Text(LRFStream):
except LRFParseError:
stream.seek(oldpos)
self.content.append(self.__class__.TextTag(
if attrs:
self.content.append(self.__class__.TextTag(
'EmpLine', attrs=attrs))
def space(self, tag, stream):

View File

@ -65,7 +65,7 @@ class Resource(object):
else:
pc = url[2]
if isinstance(pc, unicode):
pc.encode('utf-8')
pc = pc.encode('utf-8')
pc = unquote(pc).decode('utf-8')
self.path = os.path.abspath(os.path.join(basedir, pc.replace('/', os.sep)))
self.fragment = unquote(url[-1])

View File

@ -7,13 +7,13 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import sys, os
from zipfile import ZipFile, BadZipfile
from calibre.utils.zipfile import ZipFile, BadZipfile
from cStringIO import StringIO
from contextlib import closing
from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup
from calibre.ebooks.metadata.opf import OPF, OPFReader
from calibre.ebooks.metadata.opf import OPF, OPFReader, OPFCreator
from calibre.ebooks.metadata import get_parser, MetaInformation
class EPubException(Exception):
pass
@ -71,9 +71,9 @@ class OCFReader(OCF):
raise EPubException("missing OPF package file")
class OCFZipReader(OCFReader):
def __init__(self, stream):
def __init__(self, stream, mode='r'):
try:
self.archive = ZipFile(stream, 'r')
self.archive = ZipFile(stream, mode)
except BadZipfile:
raise EPubException("not a ZIP .epub OCF container")
self.root = getattr(stream, 'name', os.getcwd())
@ -82,6 +82,19 @@ class OCFZipReader(OCFReader):
def open(self, name, mode='r'):
return StringIO(self.archive.read(name))
class OCFZipWriter(OCFZipReader):
def __init__(self, stream):
OCFZipReader.__init__(self, stream, mode='a')
def set_metadata(self, mi):
name = self.container[OPF.MIMETYPE]
stream = StringIO()
opf = OPFCreator(self.root, mi)
opf.render(stream)
self.archive.delete(name)
self.archive.writestr(name, stream.getvalue())
class OCFDirReader(OCFReader):
def __init__(self, path):
self.root = path
@ -95,13 +108,35 @@ def get_metadata(stream):
""" Return metadata as a L{MetaInfo} object """
return OCFZipReader(stream).opf
def main(args=sys.argv):
if len(args) != 2 or '--help' in args or '-h' in args:
print >>sys.stderr, _('Usage:'), args[0], _('mybook.epub')
return 1
def set_metadata(stream, mi):
OCFZipWriter(stream).set_metadata(mi)
path = os.path.abspath(os.path.expanduser(args[1]))
print unicode(get_metadata(open(path, 'rb')))
def option_parser():
parser = get_parser('epub')
parser.remove_option('--category')
parser.add_option('--tags', default=None, help=_('A comma separated list of tags to set'))
return parser
def main(args=sys.argv):
parser = option_parser()
opts, args = parser.parse_args(args)
if len(args) != 2:
parser.print_help()
return 1
stream = open(args[1], 'r+b')
mi = MetaInformation(OCFZipReader(stream).opf)
if opts.title:
mi.title = opts.title
if opts.authors:
mi.authors = opts.authors.split(',')
if opts.tags:
mi.tags = opts.tags.split(',')
if opts.comment:
mi.comments = opts.comment
set_metadata(stream, mi)
print unicode(mi)
return 0
if __name__ == '__main__':

View File

@ -140,7 +140,7 @@ def main(args=sys.argv):
return 1
for book in create_books(opts, args):
print unicode(book)
print unicode(book).encode('utf-8')
return 0

View File

@ -14,6 +14,7 @@ from calibre.ebooks.mobi.reader import get_metadata as mobi_metadata
from calibre.ebooks.metadata.opf import OPFReader
from calibre.ebooks.metadata.rtf import set_metadata as set_rtf_metadata
from calibre.ebooks.lrf.meta import set_metadata as set_lrf_metadata
from calibre.ebooks.metadata.epub import set_metadata as set_epub_metadata
from calibre.ebooks.metadata import MetaInformation
@ -88,6 +89,8 @@ def set_metadata(stream, mi, stream_type='lrf'):
if stream_type: stream_type = stream_type.lower()
if stream_type == 'lrf':
set_lrf_metadata(stream, mi)
elif stream_type == 'epub':
set_epub_metadata(stream, mi)
elif stream_type == 'rtf':
set_rtf_metadata(stream, mi)

View File

@ -20,7 +20,7 @@ class NCXSoup(BeautifulStoneSoup):
class TOC(list):
def __init__(self, href=None, fragment=None, text=None, parent=None, play_order=1,
def __init__(self, href=None, fragment=None, text=None, parent=None, play_order=0,
base_path=os.getcwd()):
self.href = href
self.fragment = fragment
@ -30,7 +30,9 @@ class TOC(list):
self.play_order = play_order
def add_item(self, href, fragment, text):
self.append(TOC(href=href, fragment=fragment, text=text, parent=self, base_path=self.base_path))
play_order = (self[-1].play_order if len(self) else self.play_order) + 1
self.append(TOC(href=href, fragment=fragment, text=text, parent=self,
base_path=self.base_path, play_order=play_order))
return self[-1]
def top_level_items(self):

View File

@ -66,6 +66,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
single_format = settings.get('save to disk single format', 'lrf')
self.single_format.setCurrentIndex(BOOK_EXTENSIONS.index(single_format))
self.cover_browse.setValue(settings.get('cover flow queue length', 6))
self.confirm_delete.setChecked(settings.get('confirm delete', False))
def compact(self, toggled):
d = Vacuum(self, self.db)
@ -95,6 +96,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.final_columns = [self.columns.item(i).checkState() == Qt.Checked for i in range(self.columns.count())]
settings.set('toolbar icon size', self.ICON_SIZES[self.toolbar_button_size.currentIndex()])
settings.set('show text in toolbar', bool(self.show_toolbar_text.isChecked()))
settings.set('confirm delete', bool(self.confirm_delete.isChecked()))
pattern = self.filename_pattern.commit()
settings.set('filename pattern', pattern)
settings.set('save to disk single format', BOOK_EXTENSIONS[self.single_format.currentIndex()])

View File

@ -83,7 +83,7 @@
<x>0</x>
<y>0</y>
<width>595</width>
<height>638</height>
<height>640</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
@ -159,6 +159,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="confirm_delete" >
<property name="text" >
<string>Ask for &amp;confirmation before deleting files</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_2" >
<item row="0" column="0" >

View File

@ -126,7 +126,7 @@ class ConversionJob(Job):
def formatted_error(self):
if self.exception is None:
return ''
ans = u'<p><b>%s</b>:'%self.exception
ans = u'<p><b>%s</b>:'%repr(self.exception)
ans += '<h2>Traceback:</h2><pre>%s</pre>'%self.last_traceback
return ans

View File

@ -548,6 +548,12 @@ class Main(MainWindow, Ui_MainWindow):
rows = view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
return
if Settings().get('confirm delete', False):
d = question_dialog(self, _('Confirm delete'),
_('Are you sure you want to delete these %d books?')%len(rows))
if d.exec_() != QMessageBox.Yes:
return
if self.stack.currentIndex() == 0:
view.model().delete_books(rows)
else:

View File

@ -1,46 +0,0 @@
TARGET = pictureflow.so
OFILES = sippictureflowcmodule.o sippictureflowPictureFlow.o
HFILES = sipAPIpictureflow.h
CC = gcc
CXX = g++
LINK = g++
CPPFLAGS = -DQT_NO_DEBUG -DQT_THREAD_SUPPORT -I. -I/usr/include/python2.5 -I/usr/lib/qt-3.3/mkspecs/default -I/usr/lib/qt-3.3/include
CFLAGS = -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables -fPIC -Wall -W -D_REENTRANT
CXXFLAGS = -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables -fPIC -Wall -W -D_REENTRANT
LFLAGS = -shared -Wl,--version-script=pictureflow.exp
LIBS = -L.. -L/usr/lib/qt-3.3/lib -lpictureflow -lqt-mt -lXext -lX11 -lm -lpthread
MOC = /usr/lib/qt-3.3/bin/moc
.SUFFIXES: .c .o .cpp .cc .cxx .C
.cpp.o:
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $<
.cc.o:
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $<
.cxx.o:
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $<
.C.o:
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $@ $<
.c.o:
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
$(TARGET): $(OFILES)
@echo '{ global: initpictureflow; local: *; };' > pictureflow.exp
$(LINK) $(LFLAGS) -o $(TARGET) $(OFILES) $(LIBS)
$(OFILES): $(HFILES)
install: $(TARGET)
@test -d $(DESTDIR)/usr/lib/python2.5/site-packages || mkdir -p $(DESTDIR)/usr/lib/python2.5/site-packages
cp -f $(TARGET) $(DESTDIR)/usr/lib/python2.5/site-packages/$(TARGET)
clean:
-rm -f $(TARGET)
-rm -f sippictureflowcmodule.o
-rm -f sippictureflowPictureFlow.o
-rm -f pictureflow.exp

View File

@ -1,5 +1,4 @@
import os, sys, glob, shutil
import sipconfig
import os, sys, glob
if os.environ.get('PYQT4PATH', None):
print os.environ['PYQT4PATH']
sys.path.insert(0, os.environ['PYQT4PATH'])
@ -32,34 +31,22 @@ makefile = pyqtconfig.QtGuiModuleMakefile (
qt=1,
)
# Add the library we are wrapping. The name doesn't include any platform
# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the
# ".dll" extension on Windows).
if 'linux' in sys.platform:
for f in glob.glob('../../.build/libpictureflow.a'):
shutil.copyfile(f, os.path.basename(f))
makefile.extra_lib_dirs = ['.']
else:
makefile.extra_lib_dirs = ['..\\..\\.build\\release', '../../.build', '.']
makefile.extra_libs = ['pictureflow0' if 'win' in sys.platform and 'darwin' not in sys.platform else "pictureflow"]
makefile.extra_cflags = ['-arch i386', '-arch ppc'] if 'darwin' in sys.platform else []
makefile.extra_lflags = ['-arch i386', '-arch ppc'] if 'darwin' in sys.platform else []
# Setup the platform dependent Makefile parameters
d = os.path.dirname
if 'darwin' in sys.platform:
makefile.extra_cflags += ['-arch i386', '-arch ppc']
makefile.extra_lflags += ['-arch i386', '-arch ppc']
qtdir = os.path.join(d(d(os.getcwd())), '.build')
if 'win32' in sys.platform:
qtdir = os.path.join(qtdir, 'release')
makefile.extra_lib_dirs += ['C:/Python25/libs']
# Add the compiled Qt objects
qtobjs = map(lambda x:'"'+x+'"', glob.glob(os.path.join(qtdir, '*.o')))
makefile.extra_lflags += qtobjs
makefile.extra_cxxflags = makefile.extra_cflags
# Generate the Makefile itself.
makefile.generate()
# Now we create the configuration module. This is done by merging a Python
# dictionary (whose values are normally determined dynamically) with a
# (static) template.
content = {
# Publish where the SIP specifications for this module will be
# installed.
"pictureflow_sip_dir": config.default_sip_dir,
}
# This creates the helloconfig.py module from the helloconfig.py.in
# template and the dictionary.
sipconfig.create_config_module("pictureflowconfig.py", "../pictureflowconfig.py.in", content)

View File

@ -1,22 +0,0 @@
from PyQt4 import pyqtconfig
class Configuration(pyqtconfig.Configuration):
def __init__(self, sub_cfg=None):
"""Initialise an instance of the class.
sub_cfg is the list of sub-class configurations. It should be None
when called normally.
"""
# This is all standard code to be copied verbatim except for the
# name of the module containing the super-class.
if sub_cfg:
cfg = sub_cfg
else:
cfg = []
cfg.append(_pkg_config)
pyqtconfig.Configuration.__init__(self, cfg)

View File

@ -1,6 +1,6 @@
TARGET = pictureflow
TARGET = pictureflow
TEMPLATE = lib
HEADERS = pictureflow.h
SOURCES = pictureflow.cpp
VERSION = 0.2.0
CONFIG += x86 ppc
HEADERS = pictureflow.h
SOURCES = pictureflow.cpp
VERSION = 1.0.0
CONFIG += x86 ppc

View File

@ -778,7 +778,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
isbn
FROM books;
''')
conn.execute('pragma user_version=5')
conn.execute('pragma user_version=12')
conn.commit()
def __init__(self, dbpath, row_factory=False):

View File

@ -3,8 +3,6 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
import os
from cStringIO import StringIO
from calibre.utils import zipfile
def update(pathtozip, patterns, filepaths, names, compression=zipfile.ZIP_DEFLATED, verbose=True):
@ -42,34 +40,4 @@ def extract(filename, dir):
Extract archive C{filename} into directory C{dir}
"""
zf = zipfile.ZipFile( filename )
namelist = zf.namelist()
dirlist = filter( lambda x: x.endswith( '/' ), namelist )
filelist = filter( lambda x: not x.endswith( '/' ), namelist )
# make base
pushd = os.getcwd()
if not os.path.isdir( dir ):
os.mkdir( dir )
os.chdir( dir )
# create directory structure
dirlist.sort()
for dirs in dirlist:
dirs = dirs.split( '/' )
prefix = ''
for dir in dirs:
dirname = os.path.join( prefix, dir )
if dir and not os.path.isdir( dirname ):
os.mkdir( dirname )
prefix = dirname
# extract files
for fn in filelist:
if os.path.dirname(fn) and not os.path.exists(os.path.dirname(fn)):
os.makedirs(os.path.dirname(fn))
out = open( fn, 'wb' )
buffer = StringIO( zf.read( fn ))
buflen = 2 ** 20
datum = buffer.read( buflen )
while datum:
out.write( datum )
datum = buffer.read( buflen )
out.close()
os.chdir( pushd )
zf.extractall(dir)

View File

@ -47,6 +47,7 @@ entry_points = {
'mobi2oeb = calibre.ebooks.mobi.reader:main',
'lrf2html = calibre.ebooks.lrf.html.convert_to:main',
'lit2oeb = calibre.ebooks.lit.reader:main',
'comic2lrf = calibre.ebooks.lrf.comic.convert_from:main',
'calibre-debug = calibre.debug:main',
'calibredb = calibre.library.cli:main',
'calibre-fontconfig = calibre.utils.fontconfig:main',
@ -165,6 +166,8 @@ def setup_completion(fatal_errors):
from calibre.web.feeds.main import option_parser as feeds2disk
from calibre.web.feeds.recipes import titles as feed_titles
from calibre.ebooks.lrf.feeds.convert_from import option_parser as feeds2lrf
from calibre.ebooks.metadata.epub import option_parser as epub_meta
from calibre.ebooks.lrf.comic.convert_from import option_parser as comicop
f = open_file('/etc/bash_completion.d/libprs500')
f.close()
@ -192,11 +195,12 @@ def setup_completion(fatal_errors):
f.write(opts_and_exts('pdf-meta', metaop, ['pdf']))
f.write(opts_and_exts('lit-meta', metaop, ['lit']))
f.write(opts_and_exts('opf-meta', metaop, ['opf']))
f.write(opts_and_exts('epub-meta', metaop, ['epub']))
f.write(opts_and_exts('epub-meta', epub_meta, ['epub']))
f.write(opts_and_exts('lrfviewer', lrfviewerop, ['lrf']))
f.write(opts_and_exts('pdfrelow', pdfhtmlop, ['pdf']))
f.write(opts_and_exts('mobi2oeb', mobioeb, ['mobi', 'prc']))
f.write(opts_and_exts('lit2oeb', lit2oeb, ['lit']))
f.write(opts_and_exts('comic2lrf', comicop, ['cbz', 'cbr']))
f.write(opts_and_words('feeds2disk', feeds2disk, feed_titles))
f.write(opts_and_words('feeds2lrf', feeds2lrf, feed_titles))
f.write('''

View File

@ -251,8 +251,14 @@ def download_tarball():
except ValueError:
print 'Downloading calibre...'
pb = None
src = urllib2.urlopen(MOBILEREAD+'calibre-%version-i686.tar.bz2')
size = int(src.info()['content-length'])
local = 'calibre-test.tar.bz2'
src = open(local) if os.access(local, os.R_OK) else urllib2.urlopen(MOBILEREAD+'calibre-%version-i686.tar.bz2')
if hasattr(src, 'info'):
size = int(src.info()['content-length'])
else:
src.seek(0, 2)
size = src.tell()
src.seek(0)
f = tempfile.NamedTemporaryFile()
while f.tell() < size:
f.write(src.read(4*1024))

View File

@ -131,13 +131,19 @@ Why does |app| show only some of my fonts on OS X?
The graphical user interface of |app| is not starting on Windows?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you've never used the graphical user interface before, try deleting the file library1.db (it will be somewhere under :file:`C:\\Documents and Settings` on Windows XP and :file:`C:\\Users` on Windows Vista. If that doesn't fix the problem, locate the file calibre.log (in the same places as library1.db) and post its contents in a help message on the `Forums <http://calibre.kovidgoyal.net/discussion>`_. If you can't find either file, try using the windows find feature to search for them. If the files dont exist on your system, try the following:
There can be several causes for this:
Start a command prompt (press the windows key and R and type cmd.exe in the run dialog). At the command prompt type the following command and press Enter::
* **Any windows version**: Try running it as Administrator (Right click on the icon ans select "Run as Administrator")
* **Any windows version**: Search for the files `calibre2.ini` and `calibre.ini` on your computer and delete them. Search for the file `library1.db` and rename it (this file contains all your converted books so deleting it is not a good idea. Now try again.
* **Windows Vista**: If the folder :file:`C:\Users\Your User Name\AppData\Local\VirtualStore\Program Files\calibre` exists, delete it. Uninstall |app|. Reboot. Re-install.
* **Any windows version**: Search your computer for a folder named :file:`_ipython`. Delete it and try again.
If it still wont launch, start a command prompt (press the windows key and R; then type :command:`cmd.exe` in the Run dialog that appears). At the command prompt type the following command and press Enter::
calibre-debug -c "from calibre.gui2.main import main; main()"
Post any output you see when asking for help.
Post any output you see in a help message on the `Forums <http://calibre.kovidgoyal.net/discussion`_.
I want some feature added to |app|. What can I do?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -14,7 +14,8 @@
<div id="content" class="download">
<h1><img src="${href.chrome('/dl/images/%s_logo.png'%(distro.img,))}" valign="middle" width="60" height="80"/> $title</h1>
See the <a href="/wiki/Changelog">Changelog</a> for the changes in the latest version.
See the <a href="/wiki/Changelog">Changelog</a> for the changes in the latest version. <b>Note:</b> As of 0.4.80 this install
will not work on 64-bit CPUs. Try the precompiled binary available <a href="/download_binary">here</a> instead.
<div py:if="not distro.is_generic">
First verify that you have a sufficiently new installation of python
<pre class="wiki">python --version</pre> should return at least 2.5.1<br />

View File

@ -14,7 +14,7 @@
<div id="content" class="binary">
<h1>Download $app for Linux</h1>
<p>This binary package is compatible with most recent linux distributions running on Intel 32 bit CPUs.</p>
<p>This binary package is compatible with most recent linux distributions running on Intel 32 bit CPUs. It needs testing on 64 bit CPUs. </p>
<p>
<img width="50" height="50" style="border:1px red solid" src="${href.chrome('/dl/images/binary_logo.png')}" />
(Version: $version <a href="/wiki/Changelog">Changelog</a>)

View File

@ -70,8 +70,22 @@ def import_from_launchpad(url):
open(out, 'wb').write(tf.extractfile(next).read())
next = tf.next()
check_for_critical_bugs()
return 0
def check_for_critical_bugs():
if os.path.exists('.errors'):
shutil.rmtree('.errors')
pofilter = ('pofilter', '-i', '.', '-o', '.errors',
'-t', 'accelerators', '-t', 'escapes', '-t', 'variables',
'-t', 'xmltags')
subprocess.check_call(pofilter)
errs = os.listdir('.errors')
if errs:
print 'WARNING: Translation errors detected'
print 'See the .errors directory and http://translate.sourceforge.net/wiki/toolkit/using_pofilter'
def main(args=sys.argv):
if len(args) > 1:
if args[1] == 'pot':

View File

@ -426,6 +426,7 @@ msgstr ""
"Expressión regular utilizada para detectar los títulos de los capítulos. "
"Busca las marcas de encabezado (h1-h6). Por defecto: %default"
# (pofilter) escapes: escapes in original ('"h\d,class,chapter".') don't match escapes in translation ()
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:165
msgid ""
"Detect a chapter beginning at an element having the specified attribute. The "
@ -437,7 +438,7 @@ msgstr ""
"especificado. El formato para ésta espresión es tagname regexp, nombre del "
"atributo, valor del atributo regexp. Por ejemplo, para encontrar todas las "
"etiquetas de cabecera que tienen como attribute class=\"capítulo\" podría "
"usar: \"h/d,class,capítulo\". El valor por defecto es: %default"
"usar: \"h\\d,class,capítulo\". El valor por defecto es: %default"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:167
msgid ""
@ -2111,6 +2112,7 @@ msgstr "&Compartir receta"
msgid "&Load recipe from file"
msgstr "&Cargar receta desde un archivo"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:215
msgid ""
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style "
@ -2124,16 +2126,15 @@ msgid ""
"use the \"Advanced mode\" to further customize the fetch "
"process.</p></body></html>"
msgstr ""
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style "
"type=\"text/css\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:'DejaVu Sans'; font-size:10pt; "
"font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-"
"right:0px; -qt-block-indent:0; text-indent:0px;\">Crear una receta de "
"noticias básica, añadiendo un RSS Feed. Para la mayoría de los feeds, "
"necesitará utilizar el \"modo avanzado\" para una configuración mas "
"detallada del proceso de adquisición de los datos</p></body></html>"
"noticias básica, añadiendo un RSS Feed. <br /> Para la mayoría de los feeds, "
"necesitará utilizar el \"modo avanzado\" para una configuración mas detallada "
"del proceso de adquisición de los datos</p></body></html>"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/user_profiles_ui.py:219
msgid "Recipe &title:"
@ -2253,9 +2254,10 @@ msgstr "Ninguna coincidencia"
msgid "Authors:"
msgstr "Autores:"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:106
msgid "Regular expression group name (?P<authors>)"
msgstr "Nombre de grupo de expresión regular (?P<authos>)"
msgstr "Nombre de grupo de expresión regular (?P<authors>)"
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:108
msgid "Series:"
@ -2348,9 +2350,10 @@ msgstr "Formatos"
msgid "Book <font face=\"serif\">%s</font> of %s."
msgstr "Libro <font face=\"serif\">%s</font> de %s."
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:396
msgid "Double click to <b>edit</b> me<br><br>"
msgstr "Doble click para <b>editarme</b>"
msgstr "Doble click para <b>editarme</b><br><br>"
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:406
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:757
@ -2898,14 +2901,15 @@ msgstr "ERROR: Excepción no Contemplada"
msgid "Add a custom news source"
msgstr "Añadir nueva fuente de noticias"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/news.py:53
msgid ""
"<p>Please enter your username and password for %s<br>If you do not have one, "
"please subscribe to get access to the articles.<br/> Click OK to proceed."
msgstr ""
"<p>Por favor, introduzca el nombre de usuario y contraseña para %s<br/> Si "
"no tiene uno, por favor dese de alta para obtener acceso a los "
"artículos.<br/> Haga click en OK para continuar."
"<p>Por favor, introduzca el nombre de usuario y contraseña para %s<br> Si no "
"tiene uno, por favor dese de alta para obtener acceso a los artículos.<br/> "
"Haga click en OK para continuar."
#: /home/kovid/work/calibre/src/calibre/gui2/news.py:79
msgid "Custom news sources"

View File

@ -1481,6 +1481,7 @@ msgstr "Cambia l'editore di questo libro"
msgid "Ta&gs: "
msgstr "T&ag: "
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:524
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_bulk_ui.py:127
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:271
@ -1489,7 +1490,7 @@ msgid ""
"<br><br>They can be any words or phrases, separated by commas."
msgstr ""
"I tag categorizzano un libro. Questo è particolarmente utile durante le "
"ricerche. <br>Possono essere qualsiasi parola o frase, separati da una "
"ricerche. <br><br>Possono essere qualsiasi parola o frase, separati da una "
"virgola"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:525
@ -2143,6 +2144,7 @@ msgstr ""
msgid "Recipe source code (python)"
msgstr "Codice sorgente formula (python)"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:97
msgid ""
"<p>Set a regular expression pattern to use when trying to guess ebook "
@ -2154,7 +2156,7 @@ msgstr ""
"<p>Impostare un modello di espressione regolare da usare nel tentativo di "
"indovinare i metadati dei libri dal nome del file. <p>È disponibile un <a "
"href=\"http://docs.python.org/lib/re-syntax.html\">riferimento</a> sulla "
"sintassi delle espressioni regolari. Usare la funzionalità <b>Test</b> "
"sintassi delle espressioni regolari.<p> Usare la funzionalità <b>Test</b> "
"sottostante per testare le proprie espressioni regolari su una serie di nomi "
"di file di esempio."
@ -2294,9 +2296,10 @@ msgstr "Formati"
msgid "Book <font face=\"serif\">%s</font> of %s."
msgstr "Libro <font face=\"serif\">%s</font> di %s"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:396
msgid "Double click to <b>edit</b> me<br><br>"
msgstr "Doppio clic per modificarmi"
msgstr "Doppio clic per <b>modificarmi</b><br><br>"
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:406
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:757

View File

@ -332,6 +332,7 @@ msgstr ""
"De reguliere expressie die wordt gebruikt om hoofdstukken te herkennen. Deze "
"wordt gezocht in 'heading tags' (h1-h6). Standaard: %default"
# (pofilter) escapes: escapes in original ('"h\d,class,chapter".') don't match escapes in translation ('"h\d\klasse,hoofdstuk".')
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:165
msgid ""
"Detect a chapter beginning at an element having the specified attribute. The "
@ -342,8 +343,8 @@ msgstr ""
"vind het begin van een hoofdstuk bij een element met het gespecificeerde "
"attribuut. Het formaat voor deze optie is tagnaam regexp, attribuut naam, "
"attribuut waarde regexp. Bijvoorbeeld, om alle kop tags te vinden met de "
"attribuut klasse \"hoofstuk\", gebruik \"h\\d\\klasse,hoofdstuk\". Standaard "
"is %default"
"attribuut klasse \"hoofstuk\", gebruik \"h\\d,klasse,hoofdstuk\". Standaard is "
"%default"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:167
msgid ""
@ -1307,10 +1308,11 @@ msgstr "Je hebt geen permissie om het bestand te lezen: "
msgid "Error reading file"
msgstr "Fout bij het lezen van bestand"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:183
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:53
msgid "<p>There was an error reading from file: <br /><b>"
msgstr "<p>Er is een fout opgetreden bij het lezen van bestand: <br></b>"
msgstr "<p>Er is een fout opgetreden bij het lezen van bestand: <br /><b>"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:189
msgid " is not a valid picture"
@ -1733,6 +1735,7 @@ msgid "Comma separated list of tags to remove from the books. "
msgstr ""
"Lijst van tags die moeten worden verwijderd, gescheiden met komma's. "
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:235
msgid ""
"<p>Enter your username and password for <b>LibraryThing.com</b>. <br/>If you "
@ -1740,8 +1743,8 @@ msgid ""
"for free!.</p>"
msgstr ""
"<p>Geef uw gebruikersnaam en wachtwoord voor <b>LibraryThing.com</b>. "
"<br>Als u deze niet heeft, dan kunt u er gratis een krijgen door te <a "
"href='http://www.librarything.com'>registreren</a>"
"<br/>Als u deze niet heeft, dan kunt u er gratis een krijgen door te <a "
"href='http://www.librarything.com'>registreren</a>.</p>"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:265
msgid "<b>Could not fetch cover.</b><br/>"
@ -2181,26 +2184,29 @@ msgstr "Geen overeenkomst"
msgid "Authors:"
msgstr "Auteurs:"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:106
msgid "Regular expression group name (?P<authors>)"
msgstr "Reguliere expressie groep naam (?<auteurs>)"
msgstr "Reguliere expressie groep naam (?P<authors>)"
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:108
msgid "Series:"
msgstr "Serie:"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:109
msgid "Regular expression group name (?P<series>)"
msgstr "Reguliere expressie groep naam (?<serie>)"
msgstr "Reguliere expressie groep naam (?P<series>)"
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:111
msgid "Series index:"
msgstr "Serie Index"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:112
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:115
msgid "Regular expression group name (?P<series_index>)"
msgstr "Reguliere expressie groep naam (?<serie_index>)"
msgstr "Reguliere expressie groep naam (?P<series_index>)"
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:114
msgid "ISBN:"
@ -2825,13 +2831,14 @@ msgstr "FOUT: Niet-verwerkte uitzondering"
msgid "Add a custom news source"
msgstr "Voeg een persoonlijke nieuwsbron toe"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/gui2/news.py:53
msgid ""
"<p>Please enter your username and password for %s<br>If you do not have one, "
"please subscribe to get access to the articles.<br/> Click OK to proceed."
msgstr ""
"<p>Voer uw gebruikersnaam en wachtwoord voor %s in.<br>Als u er geen geeft, "
"registreer dan om toegang tot de artikelen te krijgen.<br>Klik op OK om "
"registreer dan om toegang tot de artikelen te krijgen.<br/>Klik op OK om "
"verder te gaan."
#: /home/kovid/work/calibre/src/calibre/gui2/news.py:79
@ -3447,13 +3454,14 @@ msgstr ""
"Maximum aantal level om recursief te zoeken -- de diepte om links te volgen. "
"Standaard %default"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/web/fetch/simple.py:394
msgid ""
"The maximum number of files to download. This only applies to files from <a "
"href> tags. Default is %default"
msgstr ""
"Het maximum aantal bestanden te downloaden. Dit is alleen van toepassing op "
"bestanden in <A HREF> tags. Standaard is %default"
"bestanden in <a href> tags. Standaard is %default"
#: /home/kovid/work/calibre/src/calibre/web/fetch/simple.py:396
msgid ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -33,14 +33,26 @@ except:
preferred_encoding = 'utf-8'
iswindows = 'win32' in sys.platform or 'win64' in sys.platform
isosx = 'darwin' in sys.platform
isosx = 'darwin' in sys.platform
DISABLED = False
#if isosx:
# libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c'))
# size = ctypes.c_uint(0)
# ok = libc.sysctlbyname("hw.cpu64bit_capable", None, byref(size), None, 0)
# if ok != 0:
# is64bit = False
# else:
# buf = ctypes.c_char_p("\0" * size.value)
# ok = libc.sysctlbyname("hw.cpu64bit_capable", buf, byref(size), None, 0)
# if ok != 0:
# is64bit = False
# else:
# is64bit = '1' in buf.value
# DISABLED = is64bit
def load_library():
if isosx:
if os.path.exists('/usr/X11/lib/libfontconfig.1.dylib'): # The fontconfig shipped with calibre doesn't work on Leopard
lib = '/usr/X11/lib/libfontconfig.1.dylib'
else:
lib = os.path.join(getattr(sys, 'frameworks_dir'), 'libfontconfig.1.dylib') \
lib = os.path.join(getattr(sys, 'frameworks_dir'), 'libfontconfig.1.dylib') \
if hasattr(sys, 'frameworks_dir') else util.find_library('fontconfig')
return cdll.LoadLibrary(lib)
elif iswindows:
@ -159,9 +171,9 @@ class FontScanner(Thread):
global _initialized
_initialized = True
_scanner = FontScanner()
_scanner.start()
if not DISABLED:
_scanner = FontScanner()
_scanner.start()
def join():
_scanner.join(120)
@ -177,6 +189,8 @@ def find_font_families(allowed_extensions=['ttf', 'otf']):
`allowed_extensions`: A list of allowed extensions for font file types. Defaults to
`['ttf', 'otf']`. If it is empty, it is ignored.
'''
if DISABLED:
return []
join()
allowed_extensions = [i.lower() for i in allowed_extensions]
@ -219,6 +233,8 @@ def files_for_family(family, normalize=True):
they are a tuple (slant, weight) otherwise they are strings from the set
`('normal', 'bold', 'italic', 'bi', 'light', 'li')`
'''
if DISABLED:
return {}
join()
if isinstance(family, unicode):
family = family.encode(preferred_encoding)
@ -295,6 +311,8 @@ def match(name, sort=False, verbose=False):
decreasing closeness of matching.
`verbose`: If `True` print debugging information to stdout
'''
if DISABLED:
return []
join()
if isinstance(name, unicode):
name = name.encode(preferred_encoding)

View File

@ -1,5 +0,0 @@
from distutils.core import setup, Extension
setup(name="lzx", version="1.0",
ext_modules=[Extension('lzx', sources=['lzx/lzxmodule.c', 'lzx/lzxd.c'],
include_dirs=['lzx'])])

View File

@ -1,15 +0,0 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en'
'''
Build the lzx decompressor extension
'''
from distutils.core import setup, Extension
setup(name="lzx", version="1.0",
ext_modules=[Extension('lzx',
sources=['lzxmodule.c', 'lzxd.c'],
include_dirs=['.'])])

View File

@ -0,0 +1,156 @@
/* d3des.h -
*
* Headers and defines for d3des.c
* Graven Imagery, 1992.
*
* THIS SOFTWARE PLACED IN THE PUBLIC DOMAIN BY THE AUTHOUR
* 920825 19:42 EDST
*
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
* (GEnie : OUTER; CIS : [71755,204])
*/
#undef D2_DES
#undef D3_DES
#ifdef D3_DES
#ifndef D2_DES
#define D2_DES /* D2_DES is needed for D3_DES */
#endif
#endif
#define EN0 0 /* MODE == encrypt */
#define DE1 1 /* MODE == decrypt */
/* Useful on 68000-ish machines, but NOT USED here. */
typedef union {
unsigned long blok[2];
unsigned short word[4];
unsigned char byte[8];
} M68K;
typedef union {
unsigned long dblok[4];
unsigned short dword[8];
unsigned char dbyte[16];
} M68K2;
extern void deskey(unsigned char *, short);
/* hexkey[8] MODE
* Sets the internal key register according to the hexadecimal
* key contained in the 8 bytes of hexkey, according to the DES,
* for encryption or decryption according to MODE.
*/
extern void usekey(unsigned long *);
/* cookedkey[32]
* Loads the internal key register with the data in cookedkey.
*/
extern void cpkey(unsigned long *);
/* cookedkey[32]
* Copies the contents of the internal key register into the storage
* located at &cookedkey[0].
*/
extern void des(unsigned char *, unsigned char *);
/* from[8] to[8]
* Encrypts/Decrypts (according to the key currently loaded in the
* internal key register) one block of eight bytes at address 'from'
* into the block at address 'to'. They can be the same.
*/
#ifdef D2_DES
#define desDkey(a,b) des2key((a),(b))
extern void des2key(unsigned char *, short);
/* hexkey[16] MODE
* Sets the internal key registerS according to the hexadecimal
* keyS contained in the 16 bytes of hexkey, according to the DES,
* for DOUBLE encryption or decryption according to MODE.
* NOTE: this clobbers all three key registers!
*/
extern void Ddes(unsigned char *, unsigned char *);
/* from[8] to[8]
* Encrypts/Decrypts (according to the keyS currently loaded in the
* internal key registerS) one block of eight bytes at address 'from'
* into the block at address 'to'. They can be the same.
*/
extern void D2des(unsigned char *, unsigned char *);
/* from[16] to[16]
* Encrypts/Decrypts (according to the keyS currently loaded in the
* internal key registerS) one block of SIXTEEN bytes at address 'from'
* into the block at address 'to'. They can be the same.
*/
extern void makekey(char *, unsigned char *);
/* *password, single-length key[8]
* With a double-length default key, this routine hashes a NULL-terminated
* string into an eight-byte random-looking key, suitable for use with the
* deskey() routine.
*/
#define makeDkey(a,b) make2key((a),(b))
extern void make2key(char *, unsigned char *);
/* *password, double-length key[16]
* With a double-length default key, this routine hashes a NULL-terminated
* string into a sixteen-byte random-looking key, suitable for use with the
* des2key() routine.
*/
#ifndef D3_DES /* D2_DES only */
#define useDkey(a) use2key((a))
#define cpDkey(a) cp2key((a))
extern void use2key(unsigned long *);
/* cookedkey[64]
* Loads the internal key registerS with the data in cookedkey.
* NOTE: this clobbers all three key registers!
*/
extern voi cp2key(unsigned long *);
/* cookedkey[64]
* Copies the contents of the internal key registerS into the storage
* located at &cookedkey[0].
*/
#else /* D3_DES too */
#define useDkey(a) use3key((a))
#define cpDkey(a) cp3key((a))
extern void des3key(unsigned char *, short);
/* hexkey[24] MODE
* Sets the internal key registerS according to the hexadecimal
* keyS contained in the 24 bytes of hexkey, according to the DES,
* for DOUBLE encryption or decryption according to MODE.
*/
extern void use3key(unsigned long *);
/* cookedkey[96]
* Loads the 3 internal key registerS with the data in cookedkey.
*/
extern void cp3key(unsigned long *);
/* cookedkey[96]
* Copies the contents of the 3 internal key registerS into the storage
* located at &cookedkey[0].
*/
extern void make3key(char *, unsigned char *);
/* *password, triple-length key[24]
* With a triple-length default key, this routine hashes a NULL-terminated
* string into a twenty-four-byte random-looking key, suitable for use with
* the des3key() routine.
*/
#endif /* D3_DES */
#endif /* D2_DES */
/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
********************************************************************/

View File

@ -0,0 +1,693 @@
/* D3DES (V5.09) -
*
* A portable, public domain, version of the Data Encryption Standard.
*
* Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
* Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
* code; Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
* Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
* for humouring me on.
*
* THIS SOFTWARE PLACED IN THE PUBLIC DOMAIN BY THE AUTHOUR
* 920825 19:42 EDST
*
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
* (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
*/
#include "d3des.h"
static void scrunch(unsigned char *, unsigned long *);
static void unscrun(unsigned long *, unsigned char *);
static void desfunc(unsigned long *, unsigned long *);
static void cookey(unsigned long *);
static unsigned long KnL[32] = { 0L };
/*
static unsigned long KnR[32] = { 0L };
static unsigned long Kn3[32] = { 0L };
static unsigned char Df_Key[24] = {
0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 };
*/
static unsigned short bytebit[8] = {
0200, 0100, 040, 020, 010, 04, 02, 01 };
static unsigned long bigbyte[24] = {
0x800000L, 0x400000L, 0x200000L, 0x100000L,
0x80000L, 0x40000L, 0x20000L, 0x10000L,
0x8000L, 0x4000L, 0x2000L, 0x1000L,
0x800L, 0x400L, 0x200L, 0x100L,
0x80L, 0x40L, 0x20L, 0x10L,
0x8L, 0x4L, 0x2L, 0x1L };
/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
static unsigned char pc1[56] = {
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 };
static unsigned char totrot[16] = {
1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
static unsigned char pc2[48] = {
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 };
void deskey(key, edf) /* Thanks to James Gillogly & Phil Karn! */
unsigned char *key;
short edf;
{
int i, j, l, m, n;
unsigned char pc1m[56], pcr[56];
unsigned long kn[32];
for ( j = 0; j < 56; j++ ) {
l = pc1[j];
m = l & 07;
pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
}
for( i = 0; i < 16; i++ ) {
if( edf == DE1 ) m = (15 - i) << 1;
else m = i << 1;
n = m + 1;
kn[m] = kn[n] = 0L;
for( j = 0; j < 28; j++ ) {
l = j + totrot[i];
if( l < 28 ) pcr[j] = pc1m[l];
else pcr[j] = pc1m[l - 28];
}
for( j = 28; j < 56; j++ ) {
l = j + totrot[i];
if( l < 56 ) pcr[j] = pc1m[l];
else pcr[j] = pc1m[l - 28];
}
for( j = 0; j < 24; j++ ) {
if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
}
}
cookey(kn);
return;
}
static void cookey(raw1)
unsigned long *raw1;
{
unsigned long *cook, *raw0;
unsigned long dough[32];
int i;
cook = dough;
for( i = 0; i < 16; i++, raw1++ ) {
raw0 = raw1++;
*cook = (*raw0 & 0x00fc0000L) << 6;
*cook |= (*raw0 & 0x00000fc0L) << 10;
*cook |= (*raw1 & 0x00fc0000L) >> 10;
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
*cook = (*raw0 & 0x0003f000L) << 12;
*cook |= (*raw0 & 0x0000003fL) << 16;
*cook |= (*raw1 & 0x0003f000L) >> 4;
*cook++ |= (*raw1 & 0x0000003fL);
}
usekey(dough);
return;
}
void cpkey(into)
unsigned long *into;
{
unsigned long *from, *endp;
from = KnL, endp = &KnL[32];
while( from < endp ) *into++ = *from++;
return;
}
void usekey(from)
unsigned long *from;
{
unsigned long *to, *endp;
to = KnL, endp = &KnL[32];
while( to < endp ) *to++ = *from++;
return;
}
void des(inblock, outblock)
unsigned char *inblock, *outblock;
{
unsigned long work[2];
scrunch(inblock, work);
desfunc(work, KnL);
unscrun(work, outblock);
return;
}
static void scrunch(outof, into)
unsigned char *outof;
unsigned long *into;
{
*into = (*outof++ & 0xffL) << 24;
*into |= (*outof++ & 0xffL) << 16;
*into |= (*outof++ & 0xffL) << 8;
*into++ |= (*outof++ & 0xffL);
*into = (*outof++ & 0xffL) << 24;
*into |= (*outof++ & 0xffL) << 16;
*into |= (*outof++ & 0xffL) << 8;
*into |= (*outof & 0xffL);
return;
}
static void unscrun(outof, into)
unsigned long *outof;
unsigned char *into;
{
*into++ = (*outof >> 24) & 0xffL;
*into++ = (*outof >> 16) & 0xffL;
*into++ = (*outof >> 8) & 0xffL;
*into++ = *outof++ & 0xffL;
*into++ = (*outof >> 24) & 0xffL;
*into++ = (*outof >> 16) & 0xffL;
*into++ = (*outof >> 8) & 0xffL;
*into = *outof & 0xffL;
return;
}
#include "spr.h"
/*
static unsigned long SP1[64] = {
0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
static unsigned long SP2[64] = {
0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
static unsigned long SP3[64] = {
0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
static unsigned long SP4[64] = {
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
static unsigned long SP5[64] = {
0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
static unsigned long SP6[64] = {
0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
static unsigned long SP7[64] = {
0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
static unsigned long SP8[64] = {
0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
*/
static void desfunc(block, keys)
unsigned long *block, *keys;
{
unsigned long fval, work, right, leftt;
int round;
leftt = block[0];
right = block[1];
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
right ^= work;
leftt ^= (work << 4);
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
right ^= work;
leftt ^= (work << 16);
work = ((right >> 2) ^ leftt) & 0x33333333L;
leftt ^= work;
right ^= (work << 2);
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
leftt ^= work;
right ^= (work << 8);
right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
for( round = 0; round < 8; round++ ) {
work = (right << 28) | (right >> 4);
work ^= *keys++;
fval = SP7[ work & 0x3fL];
fval |= SP5[(work >> 8) & 0x3fL];
fval |= SP3[(work >> 16) & 0x3fL];
fval |= SP1[(work >> 24) & 0x3fL];
work = right ^ *keys++;
fval |= SP8[ work & 0x3fL];
fval |= SP6[(work >> 8) & 0x3fL];
fval |= SP4[(work >> 16) & 0x3fL];
fval |= SP2[(work >> 24) & 0x3fL];
leftt ^= fval;
work = (leftt << 28) | (leftt >> 4);
work ^= *keys++;
fval = SP7[ work & 0x3fL];
fval |= SP5[(work >> 8) & 0x3fL];
fval |= SP3[(work >> 16) & 0x3fL];
fval |= SP1[(work >> 24) & 0x3fL];
work = leftt ^ *keys++;
fval |= SP8[ work & 0x3fL];
fval |= SP6[(work >> 8) & 0x3fL];
fval |= SP4[(work >> 16) & 0x3fL];
fval |= SP2[(work >> 24) & 0x3fL];
right ^= fval;
}
right = (right << 31) | (right >> 1);
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = (leftt << 31) | (leftt >> 1);
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
right ^= work;
leftt ^= (work << 8);
work = ((leftt >> 2) ^ right) & 0x33333333L;
right ^= work;
leftt ^= (work << 2);
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
leftt ^= work;
right ^= (work << 16);
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
leftt ^= work;
right ^= (work << 4);
*block++ = right;
*block = leftt;
return;
}
#ifdef D2_DES
void des2key(hexkey, mode) /* stomps on Kn3 too */
unsigned char *hexkey; /* unsigned char[16] */
short mode;
{
short revmod;
revmod = (mode == EN0) ? DE1 : EN0;
deskey(&hexkey[8], revmod);
cpkey(KnR);
deskey(hexkey, mode);
cpkey(Kn3); /* Kn3 = KnL */
return;
}
void Ddes(from, into)
unsigned char *from, *into; /* unsigned char[8] */
{
unsigned long work[2];
scrunch(from, work);
desfunc(work, KnL);
desfunc(work, KnR);
desfunc(work, Kn3);
unscrun(work, into);
return;
}
void D2des(from, into)
unsigned char *from; /* unsigned char[16] */
unsigned char *into; /* unsigned char[16] */
{
unsigned long *right, *l1, swap;
unsigned long leftt[2], bufR[2];
right = bufR;
l1 = &leftt[1];
scrunch(from, leftt);
scrunch(&from[8], right);
desfunc(leftt, KnL);
desfunc(right, KnL);
swap = *l1;
*l1 = *right;
*right = swap;
desfunc(leftt, KnR);
desfunc(right, KnR);
swap = *l1;
*l1 = *right;
*right = swap;
desfunc(leftt, Kn3);
desfunc(right, Kn3);
unscrun(leftt, into);
unscrun(right, &into[8]);
return;
}
void makekey(aptr, kptr)
char *aptr; /* NULL-terminated */
unsigned char *kptr; /* unsigned char[8] */
{
unsigned char *store;
int first, i;
unsigned long savek[96];
cpDkey(savek);
des2key(Df_Key, EN0);
for( i = 0; i < 8; i++ ) kptr[i] = Df_Key[i];
first = 1;
while( (*aptr != '\0') || first ) {
store = kptr;
for( i = 0; i < 8 && (*aptr != '\0'); i++ ) {
*store++ ^= *aptr & 0x7f;
*aptr++ = '\0';
}
Ddes(kptr, kptr);
first = 0;
}
useDkey(savek);
return;
}
void make2key(aptr, kptr)
char *aptr; /* NULL-terminated */
unsigned char *kptr; /* unsigned char[16] */
{
unsigned char *store;
int first, i;
unsigned long savek[96];
cpDkey(savek);
des2key(Df_Key, EN0);
for( i = 0; i < 16; i++ ) kptr[i] = Df_Key[i];
first = 1;
while( (*aptr != '\0') || first ) {
store = kptr;
for( i = 0; i < 16 && (*aptr != '\0'); i++ ) {
*store++ ^= *aptr & 0x7f;
*aptr++ = '\0';
}
D2des(kptr, kptr);
first = 0;
}
useDkey(savek);
return;
}
#ifndef D3_DES /* D2_DES only */
void cp2key(into)
unsigned long *into; /* unsigned long[64] */
{
unsigned long *from, *endp;
cpkey(into);
into = &into[32];
from = KnR, endp = &KnR[32];
while( from < endp ) *into++ = *from++;
return;
}
void use2key(from) /* stomps on Kn3 too */
unsigned long *from; /* unsigned long[64] */
{
unsigned long *to, *endp;
usekey(from);
from = &from[32];
to = KnR, endp = &KnR[32];
while( to < endp ) *to++ = *from++;
cpkey(Kn3); /* Kn3 = KnL */
return;
}
#else /* D3_DES too */
void des3key(hexkey, mode)
unsigned char *hexkey; /* unsigned char[24] */
short mode;
{
unsigned char *first, *third;
short revmod;
if( mode == EN0 ) {
revmod = DE1;
first = hexkey;
third = &hexkey[16];
}
else {
revmod = EN0;
first = &hexkey[16];
third = hexkey;
}
deskey(&hexkey[8], revmod);
cpkey(KnR);
deskey(third, mode);
cpkey(Kn3);
deskey(first, mode);
return;
}
void cp3key(into)
unsigned long *into; /* unsigned long[96] */
{
unsigned long *from, *endp;
cpkey(into);
into = &into[32];
from = KnR, endp = &KnR[32];
while( from < endp ) *into++ = *from++;
from = Kn3, endp = &Kn3[32];
while( from < endp ) *into++ = *from++;
return;
}
void use3key(from)
unsigned long *from; /* unsigned long[96] */
{
unsigned long *to, *endp;
usekey(from);
from = &from[32];
to = KnR, endp = &KnR[32];
while( to < endp ) *to++ = *from++;
to = Kn3, endp = &Kn3[32];
while( to < endp ) *to++ = *from++;
return;
}
static void D3des(unsigned char *, unsigned char *);
static void D3des(from, into) /* amateur theatrics */
unsigned char *from; /* unsigned char[24] */
unsigned char *into; /* unsigned char[24] */
{
unsigned long swap, leftt[2], middl[2], right[2];
scrunch(from, leftt);
scrunch(&from[8], middl);
scrunch(&from[16], right);
desfunc(leftt, KnL);
desfunc(middl, KnL);
desfunc(right, KnL);
swap = leftt[1];
leftt[1] = middl[0];
middl[0] = swap;
swap = middl[1];
middl[1] = right[0];
right[0] = swap;
desfunc(leftt, KnR);
desfunc(middl, KnR);
desfunc(right, KnR);
swap = leftt[1];
leftt[1] = middl[0];
middl[0] = swap;
swap = middl[1];
middl[1] = right[0];
right[0] = swap;
desfunc(leftt, Kn3);
desfunc(middl, Kn3);
desfunc(right, Kn3);
unscrun(leftt, into);
unscrun(middl, &into[8]);
unscrun(right, &into[16]);
return;
}
void make3key(aptr, kptr)
char *aptr; /* NULL-terminated */
unsigned char *kptr; /* unsigned char[24] */
{
unsigned char *store;
int first, i;
unsigned long savek[96];
cp3key(savek);
des3key(Df_Key, EN0);
for( i = 0; i < 24; i++ ) kptr[i] = Df_Key[i];
first = 1;
while( (*aptr != '\0') || first ) {
store = kptr;
for( i = 0; i < 24 && (*aptr != '\0'); i++ ) {
*store++ ^= *aptr & 0x7f;
*aptr++ = '\0';
}
D3des(kptr, kptr);
first = 0;
}
use3key(savek);
return;
}
#endif /* D3_DES */
#endif /* D2_DES */
/* Validation sets:
*
* Single-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef
* Plain : 0123 4567 89ab cde7
* Cipher : c957 4425 6a5e d31d
*
* Double-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cde7
* Cipher : 7f1d 0a77 826b 8aff
*
* Double-length key, double-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
* Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
*
* Triple-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
* Plain : 0123 4567 89ab cde7
* Cipher : de0b 7c06 ae5e 0ed5
*
* Triple-length key, double-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
* Plain : 0123 4567 89ab cdef 0123 4567 89ab cdff
* Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
*
* d3des V5.09 rwo 9208.04 20:31 Graven Imagery
**********************************************************************/

View File

@ -0,0 +1,98 @@
/* __license__ = 'GPL v3'
* __copyright__ = '2008, Marshall T. Vandegrift <llasram@gmail.com>'
*
* Python module C glue code.
*/
#include <Python.h>
#include <d3des.h>
static char msdes_doc[] =
"Provide LIT-specific DES en/decryption.";
static PyObject *MsDesError = NULL;
static PyObject *
msdes_deskey(PyObject *self, PyObject *args)
{
unsigned char *key = NULL;
unsigned int len = 0;
short int edf = 0;
if (!PyArg_ParseTuple(args, "s#h", &key, &len, &edf)) {
return NULL;
}
if (len != 8) {
PyErr_SetString(MsDesError, "Key length incorrect");
return NULL;
}
if ((edf != EN0) && (edf != DE1)) {
PyErr_SetString(MsDesError, "En/decryption direction invalid");
return NULL;
}
deskey(key, edf);
Py_RETURN_NONE;
}
static PyObject *
msdes_des(PyObject *self, PyObject *args)
{
unsigned char *inbuf = NULL;
unsigned char *outbuf = NULL;
unsigned int len = 0;
unsigned int off = 0;
PyObject *retval = NULL;
if (!PyArg_ParseTuple(args, "s#", &inbuf, &len)) {
return NULL;
}
if ((len == 0) || ((len % 8) != 0)) {
PyErr_SetString(MsDesError,
"Input length not a multiple of the block size");
return NULL;
}
retval = PyString_FromStringAndSize(NULL, len);
if (retval == NULL) {
return NULL;
}
outbuf = (unsigned char *)PyString_AS_STRING(retval);
for (off = 0; off < len; off += 8) {
des((inbuf + off), (outbuf + off));
}
return retval;
}
static PyMethodDef msdes_methods[] = {
{ "deskey", &msdes_deskey, METH_VARARGS, "Provide a new key for DES en/decryption." },
{ "des", &msdes_des, METH_VARARGS, "Perform DES en/decryption." },
{ NULL, NULL }
};
PyMODINIT_FUNC
initmsdes(void)
{
PyObject *m;
m = Py_InitModule3("msdes", msdes_methods, msdes_doc);
if (m == NULL) {
return;
}
MsDesError = PyErr_NewException("msdes.MsDesError", NULL, NULL);
Py_INCREF(MsDesError);
PyModule_AddObject(m, "MsDesError", MsDesError);
PyModule_AddObject(m, "EN0", PyInt_FromLong(EN0));
PyModule_AddObject(m, "DE1", PyInt_FromLong(DE1));
return;
}

View File

@ -0,0 +1,202 @@
/* crypto/des/spr.h */
/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
static unsigned long SP1[64] = {
0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L,
0x02000000L, 0x00080802L, 0x00080002L, 0x02000002L,
0x00080802L, 0x02080800L, 0x02080000L, 0x00000802L,
0x02000802L, 0x02000000L, 0x00000000L, 0x00080002L,
0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L,
0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L,
0x00000002L, 0x00000800L, 0x00080800L, 0x02080002L,
0x00000800L, 0x02000802L, 0x02080002L, 0x00000000L,
0x00000000L, 0x02080802L, 0x02000800L, 0x00080002L,
0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L,
0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L,
0x00080802L, 0x00000002L, 0x02000002L, 0x02080000L,
0x02080802L, 0x00080800L, 0x02080000L, 0x02000802L,
0x02000000L, 0x00000802L, 0x00080002L, 0x00000000L,
0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L,
0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L
};
static unsigned long SP2[64] = {
0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L,
0x40000010L, 0x00008010L, 0x40008000L, 0x00108000L,
0x00008000L, 0x40100010L, 0x00000010L, 0x40008000L,
0x00100010L, 0x40108000L, 0x40100000L, 0x00000010L,
0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L,
0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L,
0x40008010L, 0x00108010L, 0x40108000L, 0x40000010L,
0x40000000L, 0x00100000L, 0x00008010L, 0x40108010L,
0x00100010L, 0x40108000L, 0x40008000L, 0x00108010L,
0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L,
0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L,
0x00008000L, 0x40000000L, 0x00108010L, 0x40008010L,
0x40108000L, 0x00008000L, 0x00000000L, 0x40000010L,
0x00000010L, 0x40108010L, 0x00108000L, 0x40100000L,
0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L,
0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L
};
static unsigned long SP3[64] = {
0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L,
0x00040001L, 0x04000000L, 0x04000101L, 0x00040100L,
0x04000100L, 0x00040000L, 0x04040000L, 0x00000001L,
0x04040101L, 0x00000101L, 0x00000001L, 0x04040001L,
0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L,
0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L,
0x04040001L, 0x04000100L, 0x00040101L, 0x04040000L,
0x00040100L, 0x00000000L, 0x04000000L, 0x00040101L,
0x04040100L, 0x00000100L, 0x00000001L, 0x00040000L,
0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L,
0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L,
0x00040001L, 0x04000000L, 0x04040101L, 0x00000001L,
0x00040101L, 0x04000001L, 0x04000000L, 0x04040101L,
0x00040000L, 0x04000100L, 0x04000101L, 0x00040100L,
0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L,
0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L
};
static unsigned long SP4[64] = {
0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L,
0x00000000L, 0x10400000L, 0x10001008L, 0x00400008L,
0x10401000L, 0x10000008L, 0x10000000L, 0x00001008L,
0x10000008L, 0x00401008L, 0x00400000L, 0x10000000L,
0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L,
0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L,
0x00001008L, 0x00000000L, 0x00400008L, 0x10401000L,
0x10001000L, 0x10400008L, 0x10401008L, 0x00400000L,
0x10400008L, 0x00001008L, 0x00400000L, 0x10000008L,
0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L,
0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L,
0x00000000L, 0x10400008L, 0x10401000L, 0x00001000L,
0x10000000L, 0x10401008L, 0x00401008L, 0x00400000L,
0x10401008L, 0x00000008L, 0x10001000L, 0x00401008L,
0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L,
0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L
};
static unsigned long SP5[64] = {
0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L,
0x08010020L, 0x08000400L, 0x00010420L, 0x08010000L,
0x00010000L, 0x00000020L, 0x08000020L, 0x00010400L,
0x08000420L, 0x08010020L, 0x08010400L, 0x00000000L,
0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L,
0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L,
0x00000020L, 0x08000420L, 0x08010420L, 0x00010020L,
0x08010000L, 0x00000400L, 0x00000420L, 0x08010400L,
0x08010400L, 0x08000420L, 0x00010020L, 0x08010000L,
0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L,
0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L,
0x00010420L, 0x08000000L, 0x00000400L, 0x00010020L,
0x08000420L, 0x00000400L, 0x00000000L, 0x08010420L,
0x08010020L, 0x08010400L, 0x00000420L, 0x00010000L,
0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L,
0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L
};
static unsigned long SP6[64] = {
0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L,
0x00200040L, 0x00002000L, 0x80002040L, 0x00200000L,
0x00002040L, 0x80202040L, 0x00202000L, 0x80000000L,
0x80002000L, 0x80000040L, 0x80200000L, 0x00202040L,
0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L,
0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L,
0x80202040L, 0x80200000L, 0x80000000L, 0x00002040L,
0x00000040L, 0x00202000L, 0x00202040L, 0x80002000L,
0x00002040L, 0x80000000L, 0x80002000L, 0x00202040L,
0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L,
0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L,
0x00200040L, 0x80202040L, 0x00202000L, 0x00000040L,
0x80202040L, 0x00202000L, 0x00200000L, 0x80002040L,
0x80000040L, 0x80200000L, 0x00202040L, 0x00000000L,
0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L,
0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L,
};
static unsigned long SP7[64] = {
0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L,
0x01004204L, 0x00004004L, 0x00004200L, 0x00000000L,
0x01000000L, 0x01000204L, 0x00000204L, 0x01004000L,
0x00000004L, 0x01004200L, 0x01004000L, 0x00000204L,
0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L,
0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L,
0x01004004L, 0x00004204L, 0x01004200L, 0x00000004L,
0x00004204L, 0x01004004L, 0x00000200L, 0x01000000L,
0x00004204L, 0x01004000L, 0x01004004L, 0x00000204L,
0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L,
0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L,
0x00000200L, 0x01000004L, 0x00000004L, 0x01000200L,
0x00000000L, 0x01000204L, 0x01000200L, 0x00004200L,
0x00000204L, 0x00004000L, 0x01004204L, 0x01000000L,
0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L,
0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L,
};
static unsigned long SP8[64] = {
0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L,
0x20020000L, 0x00800080L, 0x20800000L, 0x20820080L,
0x00000080L, 0x20000000L, 0x00820000L, 0x00020080L,
0x00820080L, 0x20020080L, 0x20000080L, 0x20800000L,
0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L,
0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L,
0x20000000L, 0x00800000L, 0x20020080L, 0x20800080L,
0x00800000L, 0x00020000L, 0x20820000L, 0x00000080L,
0x00800000L, 0x00020000L, 0x20000080L, 0x20820080L,
0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L,
0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L,
0x20820000L, 0x00000080L, 0x00800080L, 0x20020000L,
0x20820080L, 0x00800000L, 0x20800000L, 0x20000080L,
0x00820000L, 0x00020080L, 0x20020080L, 0x20800000L,
0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L,
0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
};

View File

@ -163,36 +163,50 @@ class ProgressBar:
The progress bar is colored, if the terminal supports color
output; and adjusts to the width of the terminal.
If the terminal doesn't have the required capabilities, it uses a
simple progress bar.
"""
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
def __init__(self, term, header):
self.term = term
if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
raise ValueError("Terminal isn't capable enough -- you "
"should use a simpler progress dispaly.")
self.width = self.term.COLS or 75
self.bar = term.render(self.BAR)
self.header = self.term.render(self.HEADER % header.center(self.width))
self.cleared = 1 #: true if we haven't drawn the bar yet.
def __init__(self, term, header, no_progress_bar = False):
self.term, self.no_progress_bar = term, no_progress_bar
self.fancy = self.term.CLEAR_EOL and self.term.UP and self.term.BOL
if self.fancy:
self.width = self.term.COLS or 75
self.bar = term.render(self.BAR)
self.header = self.term.render(self.HEADER % header.center(self.width))
self.cleared = 1 #: true if we haven't drawn the bar yet.
def update(self, percent, message=''):
if isinstance(message, unicode):
message = message.encode('utf-8', 'ignore')
if self.cleared:
sys.stdout.write(self.header)
self.cleared = 0
n = int((self.width-10)*percent)
msg = message.center(self.width)
sys.stdout.write(
self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
(self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
self.term.CLEAR_EOL + msg)
sys.stdout.flush()
message = message.encode('utf-8', 'replace')
if self.no_progress_bar:
if message:
print message
elif self.fancy:
if self.cleared:
sys.stdout.write(self.header)
self.cleared = 0
n = int((self.width-10)*percent)
msg = message.center(self.width)
sys.stdout.write(
self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
(self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
self.term.CLEAR_EOL + msg)
sys.stdout.flush()
else:
if not message:
print '%d%%'%(percent*100),
else:
print '%d%%'%(percent*100), message
sys.stdout.flush()
def clear(self):
if not self.cleared:
if self.fancy and not self.cleared:
sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL)

View File

@ -0,0 +1,18 @@
# Makefile to test the winutil module
# Invoke with nmake /f Makefile.winutil
test : winutil.pyd
python.exe -c "import winutil; winutil.set_debug(True); print winutil.get_usb_devices(); print winutil.get_mounted_volumes_for_usb_device(0x054c, 0x031e)"
winutil.pyd : winutil.obj
link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:c:\Python25\libs \
/LIBPATH:c:\Python25\PCBuild shell32.lib setupapi.lib /EXPORT:initwinutil \
winutil.obj /OUT:winutil.pyd
winutil.obj : winutil.c
cl.exe /c /nologo /Ox /MD /W3 /GX /DNDEBUG -Ic:\Python25\include \
-Ic:\Python25\PC -Ic:\WinDDK\6001.18001\inc\api /Tcwinutil.c /Fowinutil.obj
clean :
del winutil.pyd winutil.obj winutil.exp winutil.lib

View File

@ -0,0 +1,587 @@
/*
:mod:`winutil` -- Interface to Windows
============================================
.. module:: winutil
:platform: Windows
:synopsis: Various methods to interface with the operating system
.. moduleauthor:: Kovid Goyal <kovid@kovidgoyal.net> Copyright 2008
This module contains utility functions to interface with the windows operating
system. It should be compiled with the same version of VisualStudio used to
compile python. It hasn't been tested with MinGW. We try to use unicode
wherever possible in this module.
.. exception:: winutil.DriveError
Raised when scanning for mounted volumes fails.
.. function:: is_usb_device_connected(vid : integer, pid : integer) -> bool
Return `True` iff the USB device identified by the VendorID `vid` and
ProductID `pid` is connected to the system.
.. function:: get_usb_devices() -> list of lowercase strings
Return a list of all USB devices connected to the system. Each
device is represented by a lowercase unicode string whoose format is
the windows *Device Identifier* format. See the MSDN documentation.
.. function:: get_mounted_volumes_for_usb_device(vid : integer, pid : integer) -> dictionary
Return a dictionary of the form `volume_id`:`drive_letter` for all
volumes mounted from the device specified by `vid` and `pid`.
:raises: :exception:`winutil.DriveError` if scanning fails.
.. function:: special_folder_path(csidl_id) -> path
Get paths to common system folders.
See windows documentation of SHGetFolderPath.
The paths are returned as unicode objects. `csidl_id` should be one
of the symbolic constants defined in this module. You can also `OR`
a symbolic constant with :data:`CSIDL_FLAG_CREATE` to force the operating
system to create a folder if it does not exist. For example::
>>> from winutil import *
>>> special_folder_path(CSIDL_APPDATA)
u'C:\\Documents and Settings\\Kovid Goyal\\Application Data'
>>> special_folder_path(CSIDL_PERSONAL)
u'C:\\Documents and Settings\\Kovid Goyal\\My Documents'
.. function:: argv() -> list of unicode command line arguments
Get command line arguments as unicode objects. Note that the
first argument will be the path to the interpreter, *not* the
script being run. So to replace sys.argv, you should use
sys.argv[1:] = winutil.argv()[1:].
*/
#define UNICODE
#include <Windows.h>
#include <Python.h>
#include <shlobj.h>
#include <stdio.h>
#include <setupapi.h>
#include <devguid.h>
#include <cfgmgr32.h>
#include <stdarg.h>
#define BUFSIZE 512
#define MAX_DRIVES 26
static PyObject *DriveError;
static BOOL DEBUG = FALSE;
//#define debug(fmt, ...) if DEBUG printf(x, __VA_ARGS__);
void
debug(const char *fmt, ...) {
va_list argList;
va_start(argList, fmt);
if (DEBUG) vprintf(fmt, argList);
va_end(argList);
}
struct tagDrives
{
WCHAR letter;
WCHAR volume[BUFSIZE];
};
static PyObject *
winutil_folder_path(PyObject *self, PyObject *args) {
int res; DWORD dwFlags;
PyObject *ans = NULL;
TCHAR wbuf[MAX_PATH]; CHAR buf[4*MAX_PATH];
memset(wbuf, 0, sizeof(TCHAR)*MAX_PATH); memset(buf, 0, sizeof(CHAR)*MAX_PATH);
if (!PyArg_ParseTuple(args, "l", &dwFlags)) return NULL;
res = SHGetFolderPath(NULL, dwFlags, NULL, 0, wbuf);
if (res != S_OK) {
if (res == E_FAIL) PyErr_SetString(PyExc_ValueError, "Folder does not exist.");
PyErr_SetString(PyExc_ValueError, "Folder not valid");
return NULL;
}
res = WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, 4*MAX_PATH, NULL, NULL);
ans = PyUnicode_DecodeUTF8(buf, res-1, "strict");
return ans;
}
static PyObject *
winutil_argv(PyObject *self, PyObject *args) {
PyObject *argv, *v;
LPWSTR *_argv;
LPSTR buf;
int argc, i, bytes;
if (!PyArg_ParseTuple(args, "")) return NULL;
_argv = CommandLineToArgvW(GetCommandLine(), &argc);
if (_argv == NULL) { PyErr_NoMemory(); return NULL; }
argv = PyList_New(argc);
if (argv != NULL) {
for (i = 0; i < argc; i++) {
bytes = WideCharToMultiByte(CP_UTF8, 0, _argv[i], -1, NULL, 0, NULL, NULL);
buf = (LPSTR)PyMem_Malloc(sizeof(CHAR)*bytes);
if (buf == NULL) { Py_DECREF(argv); argv = NULL; break; }
WideCharToMultiByte(CP_UTF8, 0, _argv[i], -1, buf, bytes, NULL, NULL);
v = PyUnicode_DecodeUTF8(buf, bytes-1, "strict");
PyMem_Free(buf);
if (v == NULL) { Py_DECREF(argv); argv = NULL; break; }
PyList_SetItem(argv, i, v);
}
}
LocalFree(_argv);
return argv;
}
static LPVOID
format_last_error() {
/* Format the last error as a string. The returned pointer should
be freed with :cfunction:`LocalFree(lpMsgBuf)`. It can be printed with
:cfunction:`printf("\n%ws\n", (LPCTSTR)lpMsgBuf)`.
*/
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
return lpMsgBuf;
}
static PyObject *
winutil_set_debug(PyObject *self, PyObject *args) {
PyObject *yes;
if (!PyArg_ParseTuple(args, "O", &yes)) return NULL;
DEBUG = (BOOL)PyObject_IsTrue(yes);
return Py_None;
}
static LPTSTR
get_registry_property(HDEVINFO hDevInfo, DWORD index, DWORD property, BOOL *iterate) {
/* Get a the property specified by `property` from the registry for the
* device enumerated by `index` in the collection `hDevInfo`. `iterate`
* will be set to `FALSE` if `index` points outside `hDevInfo`.
* :return: A string allocated on the heap containing the property or
* `NULL` if an error occurred.
*/
SP_DEVINFO_DATA DeviceInfoData;
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiEnumDeviceInfo(hDevInfo, index, &DeviceInfoData)) {
*iterate = FALSE;
return NULL;
}
while(!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
property,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize)) {
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
buffer = (LPTSTR)PyMem_Malloc(2*buffersize); // Twice for bug in Win2k
} else {
PyMem_Free(buffer);
PyErr_SetFromWindowsErr(0);
buffer = NULL;
break;
}
} //while
return buffer;
}
static BOOL
check_device_id(LPTSTR buffer, unsigned int vid, unsigned int pid) {
WCHAR xVid[9], dVid[9], xPid[9], dPid[9];
unsigned int j;
swprintf(xVid, L"vid_%4.4x", vid);
swprintf(dVid, L"vid_%4.4d", vid);
swprintf(xPid, L"pid_%4.4x", pid);
swprintf(dPid, L"pid_%4.4d", pid);
for (j = 0; j < wcslen(buffer); j++) buffer[j] = tolower(buffer[j]);
return ( (wcsstr(buffer, xVid) != NULL || wcsstr(buffer, dVid) != NULL ) &&
(wcsstr(buffer, xPid) != NULL || wcsstr(buffer, dPid) != NULL )
);
}
static HDEVINFO
create_device_info_set(LPGUID guid, PCTSTR enumerator, HWND parent, DWORD flags) {
HDEVINFO hDevInfo;
hDevInfo = SetupDiGetClassDevs(
guid,
enumerator,
parent,
flags
);
if (hDevInfo == INVALID_HANDLE_VALUE) {
PyErr_SetFromWindowsErr(0);
}
return hDevInfo;
}
int n;
BOOL
get_all_removable_disks(struct tagDrives *g_drives)
{
WCHAR caDrive[4];
WCHAR volume[BUFSIZE];
int nLoopIndex;
DWORD dwDriveMask;
unsigned int g_count=0;
caDrive[0] = 'A';
caDrive[1] = ':';
caDrive[2] = '\\';
caDrive[3] = 0;
// Get all drives in the system.
dwDriveMask = GetLogicalDrives();
if(dwDriveMask == 0)
{
PyErr_SetString(DriveError, "GetLogicalDrives failed");
return FALSE;
}
// Loop for all drives (MAX_DRIVES = 26)
for(nLoopIndex = 0; nLoopIndex< MAX_DRIVES; nLoopIndex++)
{
// if a drive is present,
if(dwDriveMask & 1)
{
caDrive[0] = 'A' + nLoopIndex;
// If a drive is removable
if(GetDriveType(caDrive) == DRIVE_REMOVABLE)
{
//Get its volume info and store it in the global variable.
if(GetVolumeNameForVolumeMountPoint(caDrive, volume, BUFSIZE))
{
g_drives[g_count].letter = caDrive[0];
wcscpy(g_drives[g_count].volume, volume);
g_count ++;
}
}
}
dwDriveMask >>= 1;
}
// success if atleast one removable drive is found.
if(g_count == 0)
{
PyErr_SetString(DriveError, "No removable drives found");
return FALSE;
}
return TRUE;
}
PSP_DEVICE_INTERFACE_DETAIL_DATA
get_device_grandparent(HDEVINFO hDevInfo, DWORD index, PWSTR buf, PWSTR volume_id,
BOOL *iterate) {
SP_DEVICE_INTERFACE_DATA interfaceData;
SP_DEVINFO_DATA devInfoData;
BOOL status;
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
DWORD interfaceDetailDataSize,
reqSize;
DEVINST parent;
interfaceData.cbSize = sizeof (SP_INTERFACE_DEVICE_DATA);
devInfoData.cbSize = sizeof (SP_DEVINFO_DATA);
status = SetupDiEnumDeviceInterfaces (
hDevInfo, // Interface Device Info handle
NULL, // Device Info data
(LPGUID)&GUID_DEVINTERFACE_VOLUME, // Interface registered by driver
index, // Member
&interfaceData // Device Interface Data
);
if ( status == FALSE ) {
*iterate = FALSE;
return NULL;
}
SetupDiGetDeviceInterfaceDetail (
hDevInfo, // Interface Device info handle
&interfaceData, // Interface data for the event class
NULL, // Checking for buffer size
0, // Checking for buffer size
&reqSize, // Buffer size required to get the detail data
NULL // Checking for buffer size
);
interfaceDetailDataSize = reqSize;
interfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)PyMem_Malloc(interfaceDetailDataSize+10);
if ( interfaceDetailData == NULL ) {
PyErr_NoMemory();
return NULL;
}
interfaceDetailData->cbSize = sizeof (SP_INTERFACE_DEVICE_DETAIL_DATA);
status = SetupDiGetDeviceInterfaceDetail (
hDevInfo, // Interface Device info handle
&interfaceData, // Interface data for the event class
interfaceDetailData, // Interface detail data
interfaceDetailDataSize, // Interface detail data size
&reqSize, // Buffer size required to get the detail data
&devInfoData); // Interface device info
if ( status == FALSE ) {PyErr_SetFromWindowsErr(0); PyMem_Free(interfaceDetailData); return NULL;}
// Get the device instance of parent. This points to USBSTOR.
CM_Get_Parent(&parent, devInfoData.DevInst, 0);
// Get the device ID of the USBSTORAGE volume
CM_Get_Device_ID(parent, volume_id, BUFSIZE, 0);
// Get the device instance of grand parent. This points to USB root.
CM_Get_Parent(&parent, parent, 0);
// Get the device ID of the USB root.
CM_Get_Device_ID(parent, buf, BUFSIZE, 0);
return interfaceDetailData;
}
static PyObject *
winutil_get_mounted_volumes_for_usb_device(PyObject *self, PyObject *args) {
unsigned int vid, pid, length, j;
HDEVINFO hDevInfo;
BOOL iterate = TRUE;
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetailData;
DWORD i;
WCHAR buf[BUFSIZE], volume[BUFSIZE], volume_id[BUFSIZE];
struct tagDrives g_drives[MAX_DRIVES];
PyObject *volumes, *key, *val;
if (!PyArg_ParseTuple(args, "ii", &vid, &pid)) {
return NULL;
}
volumes = PyDict_New();
if (volumes == NULL) return NULL;
for (j = 0; j < MAX_DRIVES; j++) g_drives[j].letter = 0;
// Find all removable drives
if (!get_all_removable_disks(g_drives)) {
return NULL;
}
hDevInfo = create_device_info_set((LPGUID)&GUID_DEVINTERFACE_VOLUME,
NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE) return NULL;
// Enumerate through the set
for (i=0; iterate; i++) {
interfaceDetailData = get_device_grandparent(hDevInfo, i, buf, volume_id, &iterate);
if (interfaceDetailData == NULL) {
PyErr_Print(); continue;
}
debug("Device num: %d Device Id: %ws\n\n", i, buf);
if (check_device_id(buf, vid, pid)) {
debug("Device matches\n\n");
length = wcslen(interfaceDetailData->DevicePath);
interfaceDetailData->DevicePath[length] = '\\';
interfaceDetailData->DevicePath[length+1] = 0;
if(GetVolumeNameForVolumeMountPoint(interfaceDetailData->DevicePath, volume, BUFSIZE)) {
for(j = 0; j < MAX_DRIVES; j++) {
// Compare volume mount point with the one stored earlier.
// If both match, return the corresponding drive letter.
if(g_drives[j].letter != 0 && wcscmp(g_drives[j].volume, volume)==0)
{
key = PyUnicode_FromWideChar(volume_id, wcslen(volume_id));
val = PyString_FromFormat("%c", (char)g_drives[j].letter);
if (key == NULL || val == NULL) {
PyErr_NoMemory();
PyMem_Free(interfaceDetailData);
return NULL;
}
PyDict_SetItem(volumes, key, val);
}
}
} else {
debug("Failed to get volume name for volume mount point:\n");
if (DEBUG) debug("%ws\n\n", format_last_error());
}
PyMem_Free(interfaceDetailData);
}
} //for
SetupDiDestroyDeviceInfoList(hDevInfo);
return volumes;
}
static PyObject *
winutil_get_usb_devices(PyObject *self, PyObject *args) {
unsigned int j, buffersize;
HDEVINFO hDevInfo;
DWORD i; BOOL iterate = TRUE;
PyObject *devices, *temp = (PyObject *)1;
LPTSTR buffer;
if (!PyArg_ParseTuple(args, "")) return NULL;
devices = PyList_New(0);
if (devices == NULL) {PyErr_NoMemory(); return NULL;}
// Create a Device information set with all USB devices
hDevInfo = create_device_info_set(NULL, L"USB", 0,
DIGCF_PRESENT | DIGCF_ALLCLASSES);
if (hDevInfo == INVALID_HANDLE_VALUE)
return NULL;
// Enumerate through the set
for (i=0; iterate; i++) {
buffer = get_registry_property(hDevInfo, i, SPDRP_HARDWAREID, &iterate);
if (buffer == NULL) {
PyErr_Print(); continue;
}
buffersize = wcslen(buffer);
for (j = 0; j < buffersize; j++) buffer[j] = tolower(buffer[j]);
temp = PyUnicode_FromWideChar(buffer, buffersize);
PyMem_Free(buffer);
if (temp == NULL) {
PyErr_NoMemory();
break;
}
PyList_Append(devices, temp);
} //for
if (temp == NULL) { Py_DECREF(devices); devices = NULL; }
SetupDiDestroyDeviceInfoList(hDevInfo);
return devices;
}
static PyObject *
winutil_is_usb_device_connected(PyObject *self, PyObject *args) {
unsigned int vid, pid;
HDEVINFO hDevInfo;
DWORD i; BOOL iterate = TRUE;
LPTSTR buffer;
int found = FALSE;
PyObject *ans;
if (!PyArg_ParseTuple(args, "ii", &vid, &pid)) {
return NULL;
}
// Create a Device information set with all USB devices
hDevInfo = create_device_info_set(NULL, L"USB", 0,
DIGCF_PRESENT | DIGCF_ALLCLASSES);
if (hDevInfo == INVALID_HANDLE_VALUE)
return NULL;
// Enumerate through the set
for (i=0; iterate && !found; i++) {
buffer = get_registry_property(hDevInfo, i, SPDRP_HARDWAREID, &iterate);
if (buffer == NULL) {
PyErr_Print(); continue;
}
found = check_device_id(buffer, vid, pid);
PyMem_Free(buffer);
} // for
SetupDiDestroyDeviceInfoList(hDevInfo);
ans = (found) ? Py_True : Py_False;
Py_INCREF(ans);
return ans;
}
static PyMethodDef WinutilMethods[] = {
{"special_folder_path", winutil_folder_path, METH_VARARGS,
"special_folder_path(csidl_id) -> path\n\n"
"Get paths to common system folders. "
"See windows documentation of SHGetFolderPath. "
"The paths are returned as unicode objects. csidl_id should be one "
"of the symbolic constants defined in this module. You can also OR "
"a symbolic constant with CSIDL_FLAG_CREATE to force the operating "
"system to create a folder if it does not exist."},
{"argv", winutil_argv, METH_VARARGS,
"argv() -> list of command line arguments\n\n"
"Get command line arguments as unicode objects. Note that the "
"first argument will be the path to the interpreter, *not* the "
"script being run. So to replace sys.argv, you should use "
"sys.argv[1:] = argv()[1:]."},
{"is_usb_device_connected", winutil_is_usb_device_connected, METH_VARARGS,
"is_usb_device_connected(vid, pid) -> bool\n\n"
"Check if the USB device identified by VendorID: vid (integer) and"
" ProductID: pid (integer) is currently connected."},
{"get_usb_devices", winutil_get_usb_devices, METH_VARARGS,
"get_usb_devices() -> list of strings\n\n"
"Return a list of the hardware IDs of all USB devices "
"connected to the system."},
{"get_mounted_volumes_for_usb_device", winutil_get_mounted_volumes_for_usb_device, METH_VARARGS,
"get_mounted_volumes_for_usb_device(vid, pid) -> dict\n\n"
"Return a dictionary of volume_id:drive_letter for all"
"volumes mounted on the system that belong to the"
"usb device specified by vid (integer) and pid (integer)."},
{"set_debug", winutil_set_debug, METH_VARARGS,
"set_debug(bool)\n\nSet debugging mode."
},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initwinutil(void) {
PyObject *m;
m = Py_InitModule3("winutil", WinutilMethods,
"Defines utility methods to interface with windows."
);
if (m == NULL) return;
DriveError = PyErr_NewException("winutil.DriveError", NULL, NULL);
PyModule_AddIntConstant(m, "CSIDL_ADMINTOOLS", CSIDL_ADMINTOOLS);
PyModule_AddIntConstant(m, "CSIDL_APPDATA", CSIDL_APPDATA);
PyModule_AddIntConstant(m, "CSIDL_COMMON_ADMINTOOLS", CSIDL_COMMON_ADMINTOOLS);
PyModule_AddIntConstant(m, "CSIDL_COMMON_APPDATA", CSIDL_COMMON_APPDATA);
PyModule_AddIntConstant(m, "CSIDL_COMMON_DOCUMENTS", CSIDL_COMMON_DOCUMENTS);
PyModule_AddIntConstant(m, "CSIDL_COOKIES", CSIDL_COOKIES);
PyModule_AddIntConstant(m, "CSIDL_FLAG_CREATE", CSIDL_FLAG_CREATE);
PyModule_AddIntConstant(m, "CSIDL_FLAG_DONT_VERIFY", CSIDL_FLAG_DONT_VERIFY);
PyModule_AddIntConstant(m, "CSIDL_HISTORY", CSIDL_HISTORY);
PyModule_AddIntConstant(m, "CSIDL_INTERNET_CACHE", CSIDL_INTERNET_CACHE);
PyModule_AddIntConstant(m, "CSIDL_LOCAL_APPDATA", CSIDL_LOCAL_APPDATA);
PyModule_AddIntConstant(m, "CSIDL_MYPICTURES", CSIDL_MYPICTURES);
PyModule_AddIntConstant(m, "CSIDL_PERSONAL", CSIDL_PERSONAL);
PyModule_AddIntConstant(m, "CSIDL_PROGRAM_FILES", CSIDL_PROGRAM_FILES);
PyModule_AddIntConstant(m, "CSIDL_PROGRAM_FILES_COMMON", CSIDL_PROGRAM_FILES_COMMON);
PyModule_AddIntConstant(m, "CSIDL_SYSTEM", CSIDL_SYSTEM);
PyModule_AddIntConstant(m, "CSIDL_WINDOWS", CSIDL_WINDOWS);
}

File diff suppressed because it is too large Load Diff

View File

@ -60,35 +60,15 @@ If you specify this option, any argument to %prog is ignored and a default recip
return p
def simple_progress_bar(percent, msg):
if isinstance(msg, unicode):
msg = msg.encode('utf-8', 'ignore')
if not msg:
print '%d%%'%(percent*100),
else:
print '%d%%'%(percent*100), msg
sys.stdout.flush()
def no_progress_bar(percent, msg):
print msg
class RecipeError(Exception):
pass
def run_recipe(opts, recipe_arg, parser, notification=None, handler=None):
if notification is None:
from calibre.terminfo import TerminalController, ProgressBar
from calibre.utils.terminfo import TerminalController, ProgressBar
term = TerminalController(sys.stdout)
if opts.progress_bar:
try:
pb = ProgressBar(term, _('Fetching feeds...'))
notification = pb.update
except ValueError:
notification = simple_progress_bar
print _('Fetching feeds...')
else:
notification = no_progress_bar
pb = ProgressBar(term, _('Fetching feeds...'), no_progress_bar=opts.progress_bar)
notification = pb.update
recipe, is_profile = None, False
if opts.feeds is not None:

View File

@ -20,7 +20,7 @@ from calibre.ebooks.metadata import MetaInformation
from calibre.web.feeds import feed_from_xml, templates, feeds_from_index
from calibre.web.fetch.simple import option_parser as web2disk_option_parser
from calibre.web.fetch.simple import RecursiveFetcher
from calibre.threadpool import WorkRequest, ThreadPool, NoResultsPending
from calibre.utils.threadpool import WorkRequest, ThreadPool, NoResultsPending
from calibre.ebooks.lrf.web.profiles import FullContentProfile
from calibre.ptempfile import PersistentTemporaryFile

View File

@ -29,10 +29,10 @@ BUILD_SCRIPT ='''\
#!/bin/bash
cd ~/build && \
rsync -avz --exclude src/calibre/plugins --exclude docs --exclude .bzr --exclude .build --exclude build --exclude dist --exclude "*.pyc" --exclude "*.pyo" rsync://%(host)s/work/%(project)s . && \
cd %(project)s && \
cd %(project)s && rm -rf build dist src/calibre/plugins && \
mkdir -p build dist src/calibre/plugins && \
%%s && \
rm -rf build/* dist/* && \
rm -rf build/* && \
%%s %%s
'''%dict(host=HOST, project=PROJECT)
check_call = partial(_check_call, shell=True)
@ -63,6 +63,15 @@ def start_vm(vm, ssh_host, build_script, sleep=75):
subprocess.check_call(('scp', t.name, ssh_host+':build-'+PROJECT))
subprocess.check_call('ssh -t %s bash build-%s'%(ssh_host, PROJECT), shell=True)
def run_windows_install_jammer(installer):
ibp = os.path.abspath('installer/windows')
sys.path.insert(0, ibp)
import build_installer
sys.path.remove(ibp)
build_installer.run_install_jammer(installer_name=os.path.basename(installer))
if not os.path.exists(installer):
raise Exception('Failed to run installjammer')
def build_windows(shutdown=True):
installer = installer_name('exe')
vm = '/vmware/Windows XP/Windows XP Professional.vmx'
@ -72,20 +81,14 @@ def build_windows(shutdown=True):
raise Exception('Failed to run py2exe')
if shutdown:
subprocess.Popen(('ssh', 'windows', 'shutdown', '-s', '-t', '0'))
ibp = os.path.abspath('installer/windows')
sys.path.insert(0, ibp)
import build_installer
sys.path.remove(ibp)
build_installer.run_install_jammer(installer_name=os.path.basename(installer))
if not os.path.exists(installer):
raise Exception('Failed to run installjammer')
run_windows_install_jammer(installer)
return os.path.basename(installer)
def build_osx(shutdown=True):
installer = installer_name('dmg')
vm = '/vmware/Mac OSX/Mac OSX.vmx'
python = '/Library/Frameworks/Python.framework/Versions/Current/bin/python'
start_vm(vm, 'osx', BUILD_SCRIPT%('sudo %s setup.py develop'%python, python, 'osx_installer.py'))
start_vm(vm, 'osx', (BUILD_SCRIPT%('sudo %s setup.py develop'%python, python, 'installer/osx/freeze.py')).replace('rm ', 'sudo rm '))
subprocess.check_call(('scp', 'osx:build/%s/dist/*.dmg'%PROJECT, 'dist'))
if not os.path.exists(installer):
raise Exception('Failed to build installer '+installer)
@ -97,7 +100,7 @@ def build_osx(shutdown=True):
def build_linux(shutdown=True):
installer = installer_name('tar.bz2')
vm = '/vmware/linux/libprs500-gentoo.vmx'
start_vm(vm, 'linux', BUILD_SCRIPT%('sudo python setup.py develop', 'python','linux_installer.py'))
start_vm(vm, 'linux', (BUILD_SCRIPT%('sudo python setup.py develop', 'python','installer/linux/freeze.py')).replace('rm ', 'sudo rm '))
subprocess.check_call(('scp', 'linux:/tmp/%s'%os.path.basename(installer), 'dist'))
if not os.path.exists(installer):
raise Exception('Failed to build installer '+installer)
@ -218,8 +221,8 @@ def stage_one():
os.mkdir('build')
shutil.rmtree('docs')
os.mkdir('docs')
check_call("sudo python setup.py develop", shell=True)
check_call('sudo rm src/%s/gui2/images_rc.pyc'%__appname__, shell=True)
check_call(['python', 'setup.py', 'build'])
check_call('sudo rm -f src/%s/gui2/images_rc.pyc'%__appname__, shell=True)
check_call('make', shell=True)
tag_release()
upload_demo()