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/gui2/pictureflow/release/
src/calibre/translations/compiled.py src/calibre/translations/compiled.py
installer/windows/calibre/build.log 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 PYTHON = python
all : plugins gui2 translations resources all : gui2 translations resources
plugins : src/calibre/plugins pictureflow lzx
src/calibre/plugins:
mkdir -p src/calibre/plugins
clean : clean :
cd src/calibre/gui2 && ${PYTHON} make.py clean cd src/calibre/gui2 && ${PYTHON} make.py clean
@ -25,26 +20,6 @@ resources:
manual: manual:
make -C src/calibre/manual clean html 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 : pot :
cd src/calibre/translations && ${PYTHON} __init__.py pot cd src/calibre/translations && ${PYTHON} __init__.py pot

View File

@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
''' '''
Create linux binary. 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' HOME = '/home/kovid'
PYINSTALLER = os.path.expanduser('~/build/pyinstaller') PYINSTALLER = os.path.expanduser('~/build/pyinstaller')
CALIBREPREFIX = '___' CALIBREPREFIX = '___'
@ -16,6 +16,9 @@ LIBUNRAR = '/usr/lib/libunrar.so'
QTDIR = '/usr/lib/qt4' QTDIR = '/usr/lib/qt4'
QTDLLS = ('QtCore', 'QtGui', 'QtNetwork', 'QtSvg', 'QtXml') QTDLLS = ('QtCore', 'QtGui', 'QtNetwork', 'QtSvg', 'QtXml')
EXTRAS = ('/usr/lib/python2.5/site-packages/PIL', os.path.expanduser('~/ipython/IPython')) 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') 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): 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(('/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('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()) cp = HOME+'/build/'+os.path.basename(os.getcwd())
spec = open(os.path.join(PYINSTALLER, 'calibre', 'calibre.spec'), 'wb') spec = open(os.path.join(PYINSTALLER, 'calibre', 'calibre.spec'), 'wb')
raw = re.sub(r'CALIBREPREFIX\s+=\s+\'___\'', 'CALIBREPREFIX = '+repr(cp), raw = re.sub(r'CALIBREPREFIX\s+=\s+\'___\'', 'CALIBREPREFIX = '+repr(cp),
@ -41,12 +43,14 @@ def run_pyinstaller(args=sys.argv):
spec.write(raw) spec.write(raw)
spec.close() spec.close()
os.chdir(PYINSTALLER) os.chdir(PYINSTALLER)
shutil.rmtree('calibre/dist')
os.mkdir('calibre/dist')
subprocess.check_call('python -OO Build.py calibre/calibre.spec', shell=True) subprocess.check_call('python -OO Build.py calibre/calibre.spec', shell=True)
return 0 return 0
if __name__ == '__main__' and 'linux_installer.py' in __file__: if __name__ == '__main__' and 'freeze.py' in __file__:
sys.exit(run_pyinstaller()) 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, os.path.join(sys.frozen_path, "library.pyz"))
sys.path.insert(0, sys.frozen_path) sys.path.insert(0, sys.frozen_path)
from PyQt4.QtCore import QCoreApplication 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', excludes = ['gtk._gtk', 'gtk.glade', 'qt', 'matplotlib.nxutils', 'matplotlib._cntr',
'matplotlib.ttconv', 'matplotlib._image', 'matplotlib.ft2font', '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') 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], 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() pyz = TOC()
binaries = TOC() binaries = TOC()
@ -104,11 +108,18 @@ for script, exe, a in zip(scripts, executables, analyses):
print 'Adding plugins...' print 'Adding plugins...'
for f in glob.glob(os.path.join(CALIBREPLUGINS, '*.so')): 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')] binaries += [(os.path.basename(f), f, 'BINARY')]
print 'Adding external programs...' print 'Adding external programs...'
binaries += [('clit', CLIT, 'BINARY'), ('pdftohtml', PDFTOHTML, 'BINARY'), binaries += [('clit', CLIT, 'BINARY'), ('pdftohtml', PDFTOHTML, 'BINARY'),
('libunrar.so', LIBUNRAR, 'BINARY')] ('libunrar.so', LIBUNRAR, 'BINARY')]
print 'Adding external libraries...'
binaries += [ (os.path.basename(x), x, 'BINARY') for x in (SQLITE, DBUS, LIBMNG)]
qt = [] qt = []
for dll in QTDLLS: for dll in QTDLLS:
path = os.path.join(QTDIR, 'lib'+dll+'.so.4') 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: for f in filenames:
if not f.endswith('.so') or 'designer' in dirpath or 'codcs' in dirpath or 'sqldrivers' in dirpath : continue if not f.endswith('.so') or 'designer' in dirpath or 'codcs' in dirpath or 'sqldrivers' in dirpath : continue
f = os.path.join(dirpath, f) f = os.path.join(dirpath, f)
plugins.append(('plugins/'+f.replace(plugdir, ''), f, 'BINARY')) plugins.append(('qtplugins/'+f.replace(plugdir, ''), f, 'BINARY'))
binaries += plugins binaries += plugins
manifest = '/tmp/manifest' manifest = '/tmp/manifest'

View File

@ -4,7 +4,14 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
''' Create an OSX installer ''' ''' Create an OSX installer '''
import sys, re, os, shutil, subprocess, stat, glob, zipfile 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 setuptools import setup
from py2app.build_app import py2app from py2app.build_app import py2app
from modulegraph.find_modules import find_modules from modulegraph.find_modules import find_modules
@ -40,6 +47,8 @@ loader.close()
os.chmod(loader_path, 0700) os.chmod(loader_path, 0700)
os.environ['PYTHONHOME'] = resources_dir os.environ['PYTHONHOME'] = resources_dir
os.environ['FC_CONFIG_DIR'] = os.path.join(resources_dir, 'fonts') 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) os.execv(loader_path, sys.argv)
''' '''
CHECK_SYMLINKS_PRESCRIPT = \ CHECK_SYMLINKS_PRESCRIPT = \
@ -170,64 +179,46 @@ _check_symlinks_prescript()
for f in files: 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]) 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): def add_plugins(self):
cwd = os.getcwd() self.add_qt_plugins()
qmake = '/Users/kovid/qt/bin/qmake' frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks')
files = [] plugins_dir = os.path.join(frameworks_dir, 'plugins')
try: if not os.path.exists(plugins_dir):
print 'Building pictureflow' os.mkdir(plugins_dir)
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)
return files maps = {}
finally: for f in glob.glob('src/calibre/plugins/*'):
os.chdir(cwd) 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): def run(self):
plugin_files = self.build_distutils_plugins()
py2app.run(self) py2app.run(self)
resource_dir = os.path.join(self.dist_dir, resource_dir = os.path.join(self.dist_dir,
APPNAME + '.app', 'Contents', 'Resources') APPNAME + '.app', 'Contents', 'Resources')
@ -249,8 +240,8 @@ _check_symlinks_prescript()
f.close() f.close()
os.chmod(path, stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH|stat.S_IREAD\ os.chmod(path, stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH|stat.S_IREAD\
|stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP) |stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP)
self.add_qt_plugins() self.add_plugins()
plugin_files += self.build_plugins()
print print
print 'Adding clit' print 'Adding clit'
@ -264,13 +255,8 @@ _check_symlinks_prescript()
print 'Adding plugins' print 'Adding plugins'
module_dir = os.path.join(resource_dir, 'lib', 'python2.5', 'lib-dynload') module_dir = os.path.join(resource_dir, 'lib', 'python2.5', 'lib-dynload')
print 'Adding fontconfig' 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))) 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') dst = os.path.join(resource_dir, 'fonts')
if os.path.exists(dst): if os.path.exists(dst):
shutil.rmtree(dst) shutil.rmtree(dst)
@ -281,6 +267,15 @@ _check_symlinks_prescript()
dst = os.path.join(resource_dir, 'lib', 'python2.5', 'IPython') dst = os.path.join(resource_dir, 'lib', 'python2.5', 'IPython')
if os.path.exists(dst): shutil.rmtree(dst) if os.path.exists(dst): shutil.rmtree(dst)
shutil.copytree(os.path.expanduser('~/build/ipython/IPython'), 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
print 'Installing prescipt' print 'Installing prescipt'
sf = [os.path.basename(s) for s in all_names] sf = [os.path.basename(s) for s in all_names]
@ -341,6 +336,8 @@ def main():
'NSHumanReadableCopyright':'Copyright 2008, Kovid Goyal', 'NSHumanReadableCopyright':'Copyright 2008, Kovid Goyal',
'LSEnvironment':{ 'LSEnvironment':{
'FC_CONFIG_DIR':'@executable_path/../Resources/fonts', '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 ::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 ::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 ::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 ::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 ::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 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 ::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 ::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 ::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 ::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 ::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 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 ::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 ::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 ::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 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 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> </trustInfo>
</assembly> </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): 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) 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 qtsvgdll = None
for other in self.other_depends: for other in self.other_depends:
if 'qtsvg4.dll' in other.lower(): if 'qtsvg4.dll' in other.lower():
@ -116,7 +74,7 @@ class BuildEXE(py2exe.build_exe.py2exe):
print 'Adding', qtxmldll print 'Adding', qtxmldll
shutil.copyfile(qtxmldll, shutil.copyfile(qtxmldll,
os.path.join(self.dist_dir, os.path.basename(qtxmldll))) os.path.join(self.dist_dir, os.path.basename(qtxmldll)))
print 'Adding plugins...', print 'Adding Qt plugins...',
qt_prefix = QT_DIR qt_prefix = QT_DIR
if qtsvgdll: if qtsvgdll:
qt_prefix = os.path.dirname(os.path.dirname(qtsvgdll)) qt_prefix = os.path.dirname(os.path.dirname(qtsvgdll))
@ -152,7 +110,8 @@ class BuildEXE(py2exe.build_exe.py2exe):
print '\tAdding pdftohtml' print '\tAdding pdftohtml'
shutil.copyfile(PDFTOHTML, os.path.join(PY2EXE_DIR, os.path.basename(PDFTOHTML))) shutil.copyfile(PDFTOHTML, os.path.join(PY2EXE_DIR, os.path.basename(PDFTOHTML)))
print '\tAdding ImageMagick' 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' print '\tCopying fontconfig'
for f in glob.glob(os.path.join(FONTCONFIG_DIR, '*')): for f in glob.glob(os.path.join(FONTCONFIG_DIR, '*')):
tgt = os.path.join(PY2EXE_DIR, os.path.basename(f)) 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 import sys, re, os, shutil
sys.path.append('src') 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() src = open('src/calibre/__init__.py', 'rb').read()
VERSION = re.search(r'__version__\s+=\s+[\'"]([^\'"]+)[\'"]', src).group(1) VERSION = re.search(r'__version__\s+=\s+[\'"]([^\'"]+)[\'"]', src).group(1)
APPNAME = re.search(r'__appname__\s+=\s+[\'"]([^\'"]+)[\'"]', src).group(1) APPNAME = re.search(r'__appname__\s+=\s+[\'"]([^\'"]+)[\'"]', src).group(1)
@ -44,10 +46,64 @@ main_functions = {
} }
if __name__ == '__main__': if __name__ == '__main__':
from setuptools import setup, find_packages from setuptools import setup, find_packages, Extension
import subprocess, glob import subprocess, glob
entry_points['console_scripts'].append('calibre_postinstall = calibre.linux:post_install') 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( setup(
name=APPNAME, name=APPNAME,
@ -62,6 +118,7 @@ if __name__ == '__main__':
entry_points = entry_points, entry_points = entry_points,
zip_safe = False, zip_safe = False,
options = { 'bdist_egg' : {'exclude_source_files': True,}, }, options = { 'bdist_egg' : {'exclude_source_files': True,}, },
ext_modules=ext_modules,
description = description =
''' '''
E-book management application. E-book management application.

View File

@ -1,7 +1,7 @@
''' E-book management software''' ''' E-book management software'''
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
__version__ = '0.4.79' __version__ = '0.4.80'
__docformat__ = "epytext" __docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid at kovidgoyal.net>" __author__ = "Kovid Goyal <kovid at kovidgoyal.net>"
__appname__ = 'calibre' __appname__ = 'calibre'
@ -20,7 +20,7 @@ from PyQt4.QtGui import QDesktopServices
from calibre.translations.msgfmt import make from calibre.translations.msgfmt import make
from calibre.ebooks.chardet import detect from calibre.ebooks.chardet import detect
from calibre.terminfo import TerminalController from calibre.utils.terminfo import TerminalController
terminal_controller = TerminalController(sys.stdout) terminal_controller = TerminalController(sys.stdout)
iswindows = 'win32' in sys.platform.lower() or 'win64' in sys.platform.lower() iswindows = 'win32' in sys.platform.lower() or 'win64' in sys.platform.lower()
@ -43,6 +43,41 @@ try:
except: except:
preferred_encoding = 'utf-8' 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 _abspath = os.path.abspath
def my_abspath(path, encoding=sys.getfilesystemencoding()): def my_abspath(path, encoding=sys.getfilesystemencoding()):
''' '''
@ -268,10 +303,10 @@ def filename_to_utf8(name):
def extract(path, dir): def extract(path, dir):
ext = os.path.splitext(path)[1][1:].lower() ext = os.path.splitext(path)[1][1:].lower()
extractor = None extractor = None
if ext == 'zip': if ext in ['zip', 'cbz', 'epub']:
from calibre.libunzip import extract as zipextract from calibre.libunzip import extract as zipextract
extractor = zipextract extractor = zipextract
elif ext == 'rar': elif ext in ['cbr', 'rar']:
from calibre.libunrar import extract as rarextract from calibre.libunrar import extract as rarextract
extractor = rarextract extractor = rarextract
if extractor is None: if extractor is None:
@ -605,23 +640,3 @@ if isosx:
for font in fonts: for font in fonts:
exec 'from calibre.ebooks.lrf.fonts.liberation.'+font+' import font_data' exec 'from calibre.ebooks.lrf.fonts.liberation.'+font+' import font_data'
open(os.path.join(fdir, font+'.ttf'), 'wb').write(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 return parser
def update_zipfile(zipfile, mod, path): 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]*') pat = re.compile(mod.replace('.', '/')+r'\.py[co]*')
name = mod.replace('.', '/') + os.path.splitext(path)[-1] name = mod.replace('.', '/') + os.path.splitext(path)[-1]
update(zipfile, [pat], [path], [name]) update(zipfile, [pat], [path], [name])

View File

@ -133,31 +133,7 @@ class KINDLE(Device):
def open_windows(self): def open_windows(self):
drives = [] raise NotImplementedError
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]
def open_linux(self): def open_linux(self):

View File

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

View File

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

View File

@ -7,59 +7,42 @@ manner.
import sys import sys
from calibre import iswindows, isosx from calibre import iswindows, isosx, plugins
from calibre.devices import libusb from calibre.devices import libusb
osx_scanner = None osx_scanner = win_scanner = linux_scanner = None
try:
import usbobserver
osx_scanner = usbobserver.get_devices
except ImportError:
pass
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 linux_scanner = libusb.get_devices
class DeviceScanner(object): class DeviceScanner(object):
def __init__(self, wmi=None): def __init__(self, *args):
self.wmi = wmi
if iswindows and wmi is None:
raise RuntimeError('You must pass a wmi instance to DeviceScanner on windows.')
if isosx and osx_scanner is None: if isosx and osx_scanner is None:
raise RuntimeError('The Python extension usbobserver must be available on OS X.') raise RuntimeError('The Python extension usbobserver must be available on OS X.')
if not (isosx or iswindows) and not libusb.has_library(): if not (isosx or iswindows) and not libusb.has_library():
raise RuntimeError('DeviceScanner requires libusb to work.') raise RuntimeError('DeviceScanner requires libusb to work.')
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
self.devices = [] 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): def scan(self):
try: # Windows WMI occasionally and temporarily barfs '''Fetch list of connected USB devices from operating system'''
self.devices = self.get_devices() self.devices = self.scanner()
except Exception, e:
if not iswindows and e:
raise e
def is_device_connected(self, device): def is_device_connected(self, device):
if iswindows: if iswindows:
for device_id in self.devices: for device_id in self.devices:
if 'VEN_'+device.VENDOR_NAME in device_id and \ vid, pid = 'vid_%4.4x'%device.VENDOR_ID, 'pid_%4.4x'%device.PRODUCT_ID
'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()
if vid in device_id and pid in device_id: if vid in device_id and pid in device_id:
return True return True
return False return False

View File

@ -29,7 +29,7 @@
static PyObject * static PyObject *
usbobserver_get_devices(PyObject *self, PyObject *args) { usbobserver_get_usb_devices(PyObject *self, PyObject *args) {
mach_port_t masterPort; mach_port_t masterPort;
CFMutableDictionaryRef matchingDict; CFMutableDictionaryRef matchingDict;
@ -62,7 +62,7 @@ usbobserver_get_devices(PyObject *self, PyObject *args) {
PyObject *devices, *device; PyObject *devices, *device;
devices = PyList_New(0); devices = PyList_New(0);
if (devices == NULL) { if (devices == NULL) {
PyErr_SetString(PyExc_RuntimeError, "Out of memory allocating list"); PyErr_NoMemory();
mach_port_deallocate(mach_task_self(), masterPort); mach_port_deallocate(mach_task_self(), masterPort);
return NULL; return NULL;
} }
@ -112,7 +112,7 @@ usbobserver_get_devices(PyObject *self, PyObject *args) {
} }
static PyMethodDef usbobserver_methods[] = { 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)." "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} {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 sys, struct, cStringIO, os
import functools import functools
import re
from calibre.ebooks.lit import LitError from calibre.ebooks.lit import LitError
from calibre.ebooks.lit.maps import OPF_MAP, HTML_MAP from calibre.ebooks.lit.maps import OPF_MAP, HTML_MAP
import calibre.ebooks.lit.mssha1 as mssha1 import calibre.ebooks.lit.mssha1 as mssha1
import calibre.ebooks.lit.msdes as msdes
from calibre import plugins from calibre import plugins
lzx, lxzerror = plugins['lzx'] lzx, lxzerror = plugins['lzx']
msdes, msdeserror = plugins['msdes']
OPF_DECL = """<?xml version="1.0" encoding="UTF-8" ?> OPF_DECL = """<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE package <!DOCTYPE package
@ -84,7 +85,7 @@ def read_utf8_char(bytes, pos):
if elsize + pos > len(bytes): if elsize + pos > len(bytes):
raise LitError('Invalid UTF8 character: %s' % repr(bytes[pos])) raise LitError('Invalid UTF8 character: %s' % repr(bytes[pos]))
c &= (mask - 1) c &= (mask - 1)
for i in range(1, elsize): for i in xrange(1, elsize):
b = ord(bytes[pos+i]) b = ord(bytes[pos+i])
if (b & 0xC0) != 0x80: if (b & 0xC0) != 0x80:
raise LitError( raise LitError(
@ -92,34 +93,32 @@ def read_utf8_char(bytes, pos):
c = (c << 6) | (b & 0x3F) c = (c << 6) | (b & 0x3F)
return unichr(c), pos+elsize 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): 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): def __init__(self, bin, manifest, map=OPF_MAP):
self.manifest = manifest self.manifest = manifest
self.tag_map, self.attr_map, self.tag_to_attr_map = map self.tag_map, self.attr_map, self.tag_to_attr_map = map
self.opf = map is OPF_MAP self.opf = map is OPF_MAP
self.bin = bin self.bin = bin
self.buf = cStringIO.StringIO() self.buf = cStringIO.StringIO()
self.ampersands = []
self.binary_to_text() self.binary_to_text()
self.raw = self.buf.getvalue().lstrip().decode('utf-8') self.raw = self.buf.getvalue().lstrip().decode('utf-8')
self.escape_ampersands() self.escape_ampersands()
def escape_ampersands(self): def escape_ampersands(self):
offset = 0 self.raw = self.AMPERSAND_RE.sub('&amp;', self.raw)
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
def item_path(self, internal_id): def item_path(self, internal_id):
try: try:
@ -148,8 +147,6 @@ class UnBinary(object):
continue continue
elif c == '\v': elif c == '\v':
c = '\n' c = '\n'
elif c == '&':
self.ampersands.append(self.buf.tell()-1)
self.buf.write(c.encode('utf-8')) self.buf.write(c.encode('utf-8'))
elif state == 'get flags': elif state == 'get flags':
@ -328,8 +325,11 @@ class ManifestItem(object):
self.offset = offset self.offset = offset
self.root = root self.root = root
self.state = state 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 '..' (!?) # 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:] while path.startswith('../'): path = path[3:]
self.path = path self.path = path
@ -475,7 +475,7 @@ class LitReader(object):
def _read_header_pieces(self): def _read_header_pieces(self):
src = self.header[self.hdr_len:] 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] piece = src[i * self.PIECE_SIZE:(i + 1) * self.PIECE_SIZE]
if u32(piece[4:]) != 0 or u32(piece[12:]) != 0: if u32(piece[4:]) != 0 or u32(piece[12:]) != 0:
raise LitError('Piece %s has 64bit value' % repr(piece)) raise LitError('Piece %s has 64bit value' % repr(piece))
@ -525,7 +525,7 @@ class LitReader(object):
raise LitError('Directory entry had 64bit name length.') raise LitError('Directory entry had 64bit name length.')
if namelen > remaining - 3: if namelen > remaining - 3:
raise LitError('Read past end of directory chunk') 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) section, chunk, remaining = encint(chunk, remaining)
offset, chunk, remaining = encint(chunk, remaining) offset, chunk, remaining = encint(chunk, remaining)
size, 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.num_sections = u16(raw[2:pos])
self.section_names = [""]*self.num_sections self.section_names = [""]*self.num_sections
self.section_data = [None]*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]) size = u16(raw[pos:pos+2])
pos += 2 pos += 2
size = size*2 + 2 size = size*2 + 2
@ -570,15 +570,15 @@ class LitReader(object):
if len(raw) < 5: if len(raw) < 5:
raise LitError('Truncated manifest') raise LitError('Truncated manifest')
offset, raw = u32(raw), raw[4:] offset, raw = u32(raw), raw[4:]
slen, raw = ord(raw[0]), raw[1:] internal, raw = consume_sized_utf8_string(raw)
internal, raw = raw[:slen].decode('utf8'), raw[slen:] original, raw = consume_sized_utf8_string(raw)
slen, raw = ord(raw[0]), raw[1:] # Is this last one UTF-8 or ASCIIZ?
original, raw = raw[:slen].decode('utf8'), raw[slen:] mime_type, raw = consume_sized_utf8_string(raw, zpad=True)
slen, raw = ord(raw[0]), raw[1:]
mime_type, raw = raw[:slen].decode('utf8'), raw[slen+1:]
self.manifest[internal] = ManifestItem( self.manifest[internal] = ManifestItem(
original, internal, mime_type, offset, root, state) original, internal, mime_type, offset, root, state)
mlist = self.manifest.values() mlist = self.manifest.values()
# Remove any common path elements
if len(mlist) > 1:
shared = mlist[0].path shared = mlist[0].path
for item in mlist[1:]: for item in mlist[1:]:
path = item.path path = item.path
@ -591,6 +591,10 @@ class LitReader(object):
slen = len(shared) slen = len(shared)
for item in mlist: for item in mlist:
item.path = item.path[slen:] 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): def _read_meta(self):
raw = self.get_file('/meta') raw = self.get_file('/meta')
@ -614,8 +618,8 @@ class LitReader(object):
self.drmlevel = 1 self.drmlevel = 1
else: else:
return return
des = msdes.new(self._calculate_deskey()) msdes.deskey(self._calculate_deskey(), msdes.DE1)
bookkey = des.decrypt(self.get_file('/DRMStorage/DRMSealed')) bookkey = msdes.des(self.get_file('/DRMStorage/DRMSealed'))
if bookkey[0] != '\000': if bookkey[0] != '\000':
raise LitError('Unable to decrypt title key!') raise LitError('Unable to decrypt title key!')
self.bookkey = bookkey[1:9] self.bookkey = bookkey[1:9]
@ -690,7 +694,8 @@ class LitReader(object):
def _decrypt(self, content): def _decrypt(self, content):
if self.drmlevel == 5: if self.drmlevel == 5:
raise LitError('Cannot extract content from a DRM protected ebook') 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): def _decompress(self, content, control, reset_table):
if len(control) < 32 or control[CONTROL_TAG:CONTROL_TAG+4] != "LZXC": 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 print _('OEB ebook created in'), opts.output_dir
return 0 return 0
try:
import psyco
psyco.bind(read_utf8_char)
psyco.bind(UnBinary.binary_to_text)
except ImportError:
pass
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(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']), \ bls, ls = int(self.book.defaultTextStyle.attrs['baselineskip']), \
int(self.book.defaultTextStyle.attrs['linespace']) int(self.book.defaultTextStyle.attrs['linespace'])
try: # See if line-height is a unitless number 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 fp['linespace'] = val
except ValueError: except ValueError:
val = self.unit_convert(tag_css['line-height'], pts=True, base_length='1pt') 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) css, pcss = self.parse_css(text)
ncss.update(css) ncss.update(css)
npcss.update(pcss) 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'): and tag.has_key('href'):
path = munge_paths(self.target_prefix, tag['href'])[0] path = munge_paths(self.target_prefix, tag['href'])[0]
try: try:

View File

@ -5,10 +5,11 @@ import os, sys, shutil, glob, logging
from tempfile import mkdtemp from tempfile import mkdtemp
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from calibre.ebooks.lrf import option_parser as lrf_option_parser 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 import ConversionError
from calibre.ebooks.lrf.html.convert_from import process_file as html_process_file from calibre.ebooks.lrf.html.convert_from import process_file as html_process_file
from calibre.ebooks.metadata.opf import OPFReader 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' CLIT = 'clit'
if isosx and hasattr(sys, 'frameworks_dir'): 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') CLIT = os.path.join(getattr(sys, 'frozen_path'), 'clit')
def option_parser(): def option_parser():
return lrf_option_parser( parser = lrf_option_parser(
_('''Usage: %prog [options] mybook.lit _('''Usage: %prog [options] mybook.lit
%prog converts mybook.lit to mybook.lrf''') %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): def generate_html(pathtolit, logger):
if not os.access(pathtolit, os.R_OK): if not os.access(pathtolit, os.R_OK):
raise ConversionError, 'Cannot read from ' + pathtolit raise ConversionError, 'Cannot read from ' + pathtolit
tdir = mkdtemp(prefix=__appname__+'_') tdir = mkdtemp(prefix=__appname__+'_')
os.rmdir(tdir) os.rmdir(tdir)
sep = r'\\' if iswindows else os.path.sep cmd = [CLIT, pathtolit, '%s'%(tdir+os.sep)]
cmd = ' '.join([CLIT, '"'+pathtolit+'"', '"%s"'%(tdir+sep,)]) logger.debug(repr(cmd))
logger.debug(cmd) p = Popen(cmd, stderr=PIPE, stdout=PIPE)
p = Popen(cmd, shell=True, stderr=PIPE, stdout=PIPE)
stdout = p.stdout.read() stdout = p.stdout.read()
err = p.stderr.read() err = p.stderr.read()
logger.info(p.stdout.read()) logger.info(p.stdout.read())
@ -51,7 +63,8 @@ def process_file(path, options, logger=None):
logger = logging.getLogger('lit2lrf') logger = logging.getLogger('lit2lrf')
setup_cli_handlers(logger, level) setup_cli_handlers(logger, level)
lit = os.path.abspath(os.path.expanduser(path)) 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: try:
opf = glob.glob(os.path.join(tdir, '*.opf')) opf = glob.glob(os.path.join(tdir, '*.opf'))
if opf: if opf:

View File

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

View File

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

View File

@ -7,13 +7,13 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import sys, os import sys, os
from zipfile import ZipFile, BadZipfile from calibre.utils.zipfile import ZipFile, BadZipfile
from cStringIO import StringIO from cStringIO import StringIO
from contextlib import closing from contextlib import closing
from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup 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): class EPubException(Exception):
pass pass
@ -71,9 +71,9 @@ class OCFReader(OCF):
raise EPubException("missing OPF package file") raise EPubException("missing OPF package file")
class OCFZipReader(OCFReader): class OCFZipReader(OCFReader):
def __init__(self, stream): def __init__(self, stream, mode='r'):
try: try:
self.archive = ZipFile(stream, 'r') self.archive = ZipFile(stream, mode)
except BadZipfile: except BadZipfile:
raise EPubException("not a ZIP .epub OCF container") raise EPubException("not a ZIP .epub OCF container")
self.root = getattr(stream, 'name', os.getcwd()) self.root = getattr(stream, 'name', os.getcwd())
@ -82,6 +82,19 @@ class OCFZipReader(OCFReader):
def open(self, name, mode='r'): def open(self, name, mode='r'):
return StringIO(self.archive.read(name)) 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): class OCFDirReader(OCFReader):
def __init__(self, path): def __init__(self, path):
self.root = path self.root = path
@ -95,13 +108,35 @@ def get_metadata(stream):
""" Return metadata as a L{MetaInfo} object """ """ Return metadata as a L{MetaInfo} object """
return OCFZipReader(stream).opf return OCFZipReader(stream).opf
def main(args=sys.argv): def set_metadata(stream, mi):
if len(args) != 2 or '--help' in args or '-h' in args: OCFZipWriter(stream).set_metadata(mi)
print >>sys.stderr, _('Usage:'), args[0], _('mybook.epub')
return 1
path = os.path.abspath(os.path.expanduser(args[1])) def option_parser():
print unicode(get_metadata(open(path, 'rb'))) 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 return 0
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -140,7 +140,7 @@ def main(args=sys.argv):
return 1 return 1
for book in create_books(opts, args): for book in create_books(opts, args):
print unicode(book) print unicode(book).encode('utf-8')
return 0 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.opf import OPFReader
from calibre.ebooks.metadata.rtf import set_metadata as set_rtf_metadata 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.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 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: stream_type = stream_type.lower()
if stream_type == 'lrf': if stream_type == 'lrf':
set_lrf_metadata(stream, mi) set_lrf_metadata(stream, mi)
elif stream_type == 'epub':
set_epub_metadata(stream, mi)
elif stream_type == 'rtf': elif stream_type == 'rtf':
set_rtf_metadata(stream, mi) set_rtf_metadata(stream, mi)

View File

@ -20,7 +20,7 @@ class NCXSoup(BeautifulStoneSoup):
class TOC(list): 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()): base_path=os.getcwd()):
self.href = href self.href = href
self.fragment = fragment self.fragment = fragment
@ -30,7 +30,9 @@ class TOC(list):
self.play_order = play_order self.play_order = play_order
def add_item(self, href, fragment, text): 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] return self[-1]
def top_level_items(self): 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') single_format = settings.get('save to disk single format', 'lrf')
self.single_format.setCurrentIndex(BOOK_EXTENSIONS.index(single_format)) self.single_format.setCurrentIndex(BOOK_EXTENSIONS.index(single_format))
self.cover_browse.setValue(settings.get('cover flow queue length', 6)) self.cover_browse.setValue(settings.get('cover flow queue length', 6))
self.confirm_delete.setChecked(settings.get('confirm delete', False))
def compact(self, toggled): def compact(self, toggled):
d = Vacuum(self, self.db) 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())] 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('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('show text in toolbar', bool(self.show_toolbar_text.isChecked()))
settings.set('confirm delete', bool(self.confirm_delete.isChecked()))
pattern = self.filename_pattern.commit() pattern = self.filename_pattern.commit()
settings.set('filename pattern', pattern) settings.set('filename pattern', pattern)
settings.set('save to disk single format', BOOK_EXTENSIONS[self.single_format.currentIndex()]) settings.set('save to disk single format', BOOK_EXTENSIONS[self.single_format.currentIndex()])

View File

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

View File

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

View File

@ -548,6 +548,12 @@ class Main(MainWindow, Ui_MainWindow):
rows = view.selectionModel().selectedRows() rows = view.selectionModel().selectedRows()
if not rows or len(rows) == 0: if not rows or len(rows) == 0:
return 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: if self.stack.currentIndex() == 0:
view.model().delete_books(rows) view.model().delete_books(rows)
else: 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 os, sys, glob
import sipconfig
if os.environ.get('PYQT4PATH', None): if os.environ.get('PYQT4PATH', None):
print os.environ['PYQT4PATH'] print os.environ['PYQT4PATH']
sys.path.insert(0, os.environ['PYQT4PATH']) sys.path.insert(0, os.environ['PYQT4PATH'])
@ -32,34 +31,22 @@ makefile = pyqtconfig.QtGuiModuleMakefile (
qt=1, qt=1,
) )
# Add the library we are wrapping. The name doesn't include any platform # Setup the platform dependent Makefile parameters
# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the d = os.path.dirname
# ".dll" extension on Windows). if 'darwin' in sys.platform:
if 'linux' in sys.platform: makefile.extra_cflags += ['-arch i386', '-arch ppc']
for f in glob.glob('../../.build/libpictureflow.a'): makefile.extra_lflags += ['-arch i386', '-arch ppc']
shutil.copyfile(f, os.path.basename(f)) qtdir = os.path.join(d(d(os.getcwd())), '.build')
makefile.extra_lib_dirs = ['.'] if 'win32' in sys.platform:
else: qtdir = os.path.join(qtdir, 'release')
makefile.extra_lib_dirs = ['..\\..\\.build\\release', '../../.build', '.'] makefile.extra_lib_dirs += ['C:/Python25/libs']
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 [] # Add the compiled Qt objects
makefile.extra_lflags = ['-arch i386', '-arch ppc'] if 'darwin' in sys.platform else [] qtobjs = map(lambda x:'"'+x+'"', glob.glob(os.path.join(qtdir, '*.o')))
makefile.extra_lflags += qtobjs
makefile.extra_cxxflags = makefile.extra_cflags makefile.extra_cxxflags = makefile.extra_cflags
# Generate the Makefile itself. # Generate the Makefile itself.
makefile.generate() 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

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

View File

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

View File

@ -3,8 +3,6 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os
from cStringIO import StringIO
from calibre.utils import zipfile from calibre.utils import zipfile
def update(pathtozip, patterns, filepaths, names, compression=zipfile.ZIP_DEFLATED, verbose=True): 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} Extract archive C{filename} into directory C{dir}
""" """
zf = zipfile.ZipFile( filename ) zf = zipfile.ZipFile( filename )
namelist = zf.namelist() zf.extractall(dir)
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 )

View File

@ -47,6 +47,7 @@ entry_points = {
'mobi2oeb = calibre.ebooks.mobi.reader:main', 'mobi2oeb = calibre.ebooks.mobi.reader:main',
'lrf2html = calibre.ebooks.lrf.html.convert_to:main', 'lrf2html = calibre.ebooks.lrf.html.convert_to:main',
'lit2oeb = calibre.ebooks.lit.reader:main', 'lit2oeb = calibre.ebooks.lit.reader:main',
'comic2lrf = calibre.ebooks.lrf.comic.convert_from:main',
'calibre-debug = calibre.debug:main', 'calibre-debug = calibre.debug:main',
'calibredb = calibre.library.cli:main', 'calibredb = calibre.library.cli:main',
'calibre-fontconfig = calibre.utils.fontconfig: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.main import option_parser as feeds2disk
from calibre.web.feeds.recipes import titles as feed_titles 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.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 = open_file('/etc/bash_completion.d/libprs500')
f.close() 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('pdf-meta', metaop, ['pdf']))
f.write(opts_and_exts('lit-meta', metaop, ['lit'])) f.write(opts_and_exts('lit-meta', metaop, ['lit']))
f.write(opts_and_exts('opf-meta', metaop, ['opf'])) 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('lrfviewer', lrfviewerop, ['lrf']))
f.write(opts_and_exts('pdfrelow', pdfhtmlop, ['pdf'])) f.write(opts_and_exts('pdfrelow', pdfhtmlop, ['pdf']))
f.write(opts_and_exts('mobi2oeb', mobioeb, ['mobi', 'prc'])) f.write(opts_and_exts('mobi2oeb', mobioeb, ['mobi', 'prc']))
f.write(opts_and_exts('lit2oeb', lit2oeb, ['lit'])) 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('feeds2disk', feeds2disk, feed_titles))
f.write(opts_and_words('feeds2lrf', feeds2lrf, feed_titles)) f.write(opts_and_words('feeds2lrf', feeds2lrf, feed_titles))
f.write(''' f.write('''

View File

@ -251,8 +251,14 @@ def download_tarball():
except ValueError: except ValueError:
print 'Downloading calibre...' print 'Downloading calibre...'
pb = None pb = None
src = urllib2.urlopen(MOBILEREAD+'calibre-%version-i686.tar.bz2') 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']) size = int(src.info()['content-length'])
else:
src.seek(0, 2)
size = src.tell()
src.seek(0)
f = tempfile.NamedTemporaryFile() f = tempfile.NamedTemporaryFile()
while f.tell() < size: while f.tell() < size:
f.write(src.read(4*1024)) 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? 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()" 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? I want some feature added to |app|. What can I do?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -14,7 +14,8 @@
<div id="content" class="download"> <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> <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"> <div py:if="not distro.is_generic">
First verify that you have a sufficiently new installation of python 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 /> <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"> <div id="content" class="binary">
<h1>Download $app for Linux</h1> <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> <p>
<img width="50" height="50" style="border:1px red solid" src="${href.chrome('/dl/images/binary_logo.png')}" /> <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>) (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()) open(out, 'wb').write(tf.extractfile(next).read())
next = tf.next() next = tf.next()
check_for_critical_bugs()
return 0 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): def main(args=sys.argv):
if len(args) > 1: if len(args) > 1:
if args[1] == 'pot': if args[1] == 'pot':

View File

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

View File

@ -1481,6 +1481,7 @@ msgstr "Cambia l'editore di questo libro"
msgid "Ta&gs: " msgid "Ta&gs: "
msgstr "T&ag: " 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/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_bulk_ui.py:127
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single_ui.py:271 #: /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." "<br><br>They can be any words or phrases, separated by commas."
msgstr "" msgstr ""
"I tag categorizzano un libro. Questo è particolarmente utile durante le " "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" "virgola"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:525 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single_ui.py:525
@ -2143,6 +2144,7 @@ msgstr ""
msgid "Recipe source code (python)" msgid "Recipe source code (python)"
msgstr "Codice sorgente formula (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 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:97
msgid "" msgid ""
"<p>Set a regular expression pattern to use when trying to guess ebook " "<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 " "<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 " "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 " "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 " "sottostante per testare le proprie espressioni regolari su una serie di nomi "
"di file di esempio." "di file di esempio."
@ -2294,9 +2296,10 @@ msgstr "Formati"
msgid "Book <font face=\"serif\">%s</font> of %s." msgid "Book <font face=\"serif\">%s</font> of %s."
msgstr "Libro <font face=\"serif\">%s</font> di %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 #: /home/kovid/work/calibre/src/calibre/gui2/library.py:396
msgid "Double click to <b>edit</b> me<br><br>" 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:406
#: /home/kovid/work/calibre/src/calibre/gui2/library.py:757 #: /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 " "De reguliere expressie die wordt gebruikt om hoofdstukken te herkennen. Deze "
"wordt gezocht in 'heading tags' (h1-h6). Standaard: %default" "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 #: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:165
msgid "" msgid ""
"Detect a chapter beginning at an element having the specified attribute. The " "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 " "vind het begin van een hoofdstuk bij een element met het gespecificeerde "
"attribuut. Het formaat voor deze optie is tagnaam regexp, attribuut naam, " "attribuut. Het formaat voor deze optie is tagnaam regexp, attribuut naam, "
"attribuut waarde regexp. Bijvoorbeeld, om alle kop tags te vinden met de " "attribuut waarde regexp. Bijvoorbeeld, om alle kop tags te vinden met de "
"attribuut klasse \"hoofstuk\", gebruik \"h\\d\\klasse,hoofdstuk\". Standaard " "attribuut klasse \"hoofstuk\", gebruik \"h\\d,klasse,hoofdstuk\". Standaard is "
"is %default" "%default"
#: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:167 #: /home/kovid/work/calibre/src/calibre/ebooks/lrf/__init__.py:167
msgid "" msgid ""
@ -1307,10 +1308,11 @@ msgstr "Je hebt geen permissie om het bestand te lezen: "
msgid "Error reading file" msgid "Error reading file"
msgstr "Fout bij het lezen van bestand" 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/lrf_single.py:183
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:53 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:53
msgid "<p>There was an error reading from file: <br /><b>" 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 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/lrf_single.py:189
msgid " is not a valid picture" msgid " is not a valid picture"
@ -1733,6 +1735,7 @@ msgid "Comma separated list of tags to remove from the books. "
msgstr "" msgstr ""
"Lijst van tags die moeten worden verwijderd, gescheiden met komma's. " "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 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:235
msgid "" msgid ""
"<p>Enter your username and password for <b>LibraryThing.com</b>. <br/>If you " "<p>Enter your username and password for <b>LibraryThing.com</b>. <br/>If you "
@ -1740,8 +1743,8 @@ msgid ""
"for free!.</p>" "for free!.</p>"
msgstr "" msgstr ""
"<p>Geef uw gebruikersnaam en wachtwoord voor <b>LibraryThing.com</b>. " "<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 " "<br/>Als u deze niet heeft, dan kunt u er gratis een krijgen door te <a "
"href='http://www.librarything.com'>registreren</a>" "href='http://www.librarything.com'>registreren</a>.</p>"
#: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:265 #: /home/kovid/work/calibre/src/calibre/gui2/dialogs/metadata_single.py:265
msgid "<b>Could not fetch cover.</b><br/>" msgid "<b>Could not fetch cover.</b><br/>"
@ -2181,26 +2184,29 @@ msgstr "Geen overeenkomst"
msgid "Authors:" msgid "Authors:"
msgstr "Auteurs:" 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 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:106
msgid "Regular expression group name (?P<authors>)" 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 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:108
msgid "Series:" msgid "Series:"
msgstr "Serie:" 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 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:109
msgid "Regular expression group name (?P<series>)" 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 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:111
msgid "Series index:" msgid "Series index:"
msgstr "Serie 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:112
#: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:115 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:115
msgid "Regular expression group name (?P<series_index>)" 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 #: /home/kovid/work/calibre/src/calibre/gui2/filename_pattern_ui.py:114
msgid "ISBN:" msgid "ISBN:"
@ -2825,13 +2831,14 @@ msgstr "FOUT: Niet-verwerkte uitzondering"
msgid "Add a custom news source" msgid "Add a custom news source"
msgstr "Voeg een persoonlijke nieuwsbron toe" 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 #: /home/kovid/work/calibre/src/calibre/gui2/news.py:53
msgid "" msgid ""
"<p>Please enter your username and password for %s<br>If you do not have one, " "<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." "please subscribe to get access to the articles.<br/> Click OK to proceed."
msgstr "" msgstr ""
"<p>Voer uw gebruikersnaam en wachtwoord voor %s in.<br>Als u er geen geeft, " "<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." "verder te gaan."
#: /home/kovid/work/calibre/src/calibre/gui2/news.py:79 #: /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. " "Maximum aantal level om recursief te zoeken -- de diepte om links te volgen. "
"Standaard %default" "Standaard %default"
# (pofilter) xmltags: checks that XML/HTML tags have not been translated
#: /home/kovid/work/calibre/src/calibre/web/fetch/simple.py:394 #: /home/kovid/work/calibre/src/calibre/web/fetch/simple.py:394
msgid "" msgid ""
"The maximum number of files to download. This only applies to files from <a " "The maximum number of files to download. This only applies to files from <a "
"href> tags. Default is %default" "href> tags. Default is %default"
msgstr "" msgstr ""
"Het maximum aantal bestanden te downloaden. Dit is alleen van toepassing op " "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 #: /home/kovid/work/calibre/src/calibre/web/fetch/simple.py:396
msgid "" msgid ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -34,12 +34,24 @@ except:
iswindows = 'win32' in sys.platform or 'win64' in sys.platform 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(): def load_library():
if isosx: 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') if hasattr(sys, 'frameworks_dir') else util.find_library('fontconfig')
return cdll.LoadLibrary(lib) return cdll.LoadLibrary(lib)
@ -159,7 +171,7 @@ class FontScanner(Thread):
global _initialized global _initialized
_initialized = True _initialized = True
if not DISABLED:
_scanner = FontScanner() _scanner = FontScanner()
_scanner.start() _scanner.start()
@ -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 `allowed_extensions`: A list of allowed extensions for font file types. Defaults to
`['ttf', 'otf']`. If it is empty, it is ignored. `['ttf', 'otf']`. If it is empty, it is ignored.
''' '''
if DISABLED:
return []
join() join()
allowed_extensions = [i.lower() for i in allowed_extensions] 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 they are a tuple (slant, weight) otherwise they are strings from the set
`('normal', 'bold', 'italic', 'bi', 'light', 'li')` `('normal', 'bold', 'italic', 'bi', 'light', 'li')`
''' '''
if DISABLED:
return {}
join() join()
if isinstance(family, unicode): if isinstance(family, unicode):
family = family.encode(preferred_encoding) family = family.encode(preferred_encoding)
@ -295,6 +311,8 @@ def match(name, sort=False, verbose=False):
decreasing closeness of matching. decreasing closeness of matching.
`verbose`: If `True` print debugging information to stdout `verbose`: If `True` print debugging information to stdout
''' '''
if DISABLED:
return []
join() join()
if isinstance(name, unicode): if isinstance(name, unicode):
name = name.encode(preferred_encoding) 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,15 +163,17 @@ class ProgressBar:
The progress bar is colored, if the terminal supports color The progress bar is colored, if the terminal supports color
output; and adjusts to the width of the terminal. 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' BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n' HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
def __init__(self, term, header): def __init__(self, term, header, no_progress_bar = False):
self.term = term self.term, self.no_progress_bar = term, no_progress_bar
if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL): self.fancy = self.term.CLEAR_EOL and self.term.UP and self.term.BOL
raise ValueError("Terminal isn't capable enough -- you " if self.fancy:
"should use a simpler progress dispaly.")
self.width = self.term.COLS or 75 self.width = self.term.COLS or 75
self.bar = term.render(self.BAR) self.bar = term.render(self.BAR)
self.header = self.term.render(self.HEADER % header.center(self.width)) self.header = self.term.render(self.HEADER % header.center(self.width))
@ -179,7 +181,12 @@ class ProgressBar:
def update(self, percent, message=''): def update(self, percent, message=''):
if isinstance(message, unicode): if isinstance(message, unicode):
message = message.encode('utf-8', 'ignore') message = message.encode('utf-8', 'replace')
if self.no_progress_bar:
if message:
print message
elif self.fancy:
if self.cleared: if self.cleared:
sys.stdout.write(self.header) sys.stdout.write(self.header)
self.cleared = 0 self.cleared = 0
@ -190,9 +197,16 @@ class ProgressBar:
(self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) + (self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
self.term.CLEAR_EOL + msg) self.term.CLEAR_EOL + msg)
sys.stdout.flush() sys.stdout.flush()
else:
if not message:
print '%d%%'%(percent*100),
else:
print '%d%%'%(percent*100), message
sys.stdout.flush()
def clear(self): def clear(self):
if not self.cleared: if self.fancy and not self.cleared:
sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL + sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
self.term.UP + self.term.CLEAR_EOL + self.term.UP + 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 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): class RecipeError(Exception):
pass pass
def run_recipe(opts, recipe_arg, parser, notification=None, handler=None): def run_recipe(opts, recipe_arg, parser, notification=None, handler=None):
if notification is None: if notification is None:
from calibre.terminfo import TerminalController, ProgressBar from calibre.utils.terminfo import TerminalController, ProgressBar
term = TerminalController(sys.stdout) term = TerminalController(sys.stdout)
if opts.progress_bar: pb = ProgressBar(term, _('Fetching feeds...'), no_progress_bar=opts.progress_bar)
try:
pb = ProgressBar(term, _('Fetching feeds...'))
notification = pb.update notification = pb.update
except ValueError:
notification = simple_progress_bar
print _('Fetching feeds...')
else:
notification = no_progress_bar
recipe, is_profile = None, False recipe, is_profile = None, False
if opts.feeds is not None: 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.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 option_parser as web2disk_option_parser
from calibre.web.fetch.simple import RecursiveFetcher 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.ebooks.lrf.web.profiles import FullContentProfile
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile

View File

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