CHM handler: bundle pychm for Python3
This commit is contained in:
parent
dae381f49b
commit
29e63aeda1
@ -538,7 +538,33 @@ VERSION
|
||||
# php/recoll/php_recoll.h php/recoll/recoll.cpp php/sample/shell.php
|
||||
|
||||
if MAKEPYTHON
|
||||
all-local: recollpython
|
||||
all-local: recollpython rclpychm
|
||||
install-exec-local: recollpython-install rclpychm-install
|
||||
clean-local: recollpython-clean
|
||||
else
|
||||
all-local: rclpychm
|
||||
install-exec-local: rclpychm-install
|
||||
clean-local: rclpychm-clean recollpython-clean
|
||||
endif
|
||||
|
||||
rclpychm:
|
||||
(cd python/pychm || exit 1; \
|
||||
set -x; \
|
||||
for v in 2 3;do rm -f dist/pychm-*; \
|
||||
test -n "`which python$${v}`" && python$${v} setup.py bdist_egg && \
|
||||
mv -f dist/pychm-*.egg dist/pychm$${v}.egg;\
|
||||
done \
|
||||
)
|
||||
rclpychm-install:
|
||||
(cd python/pychm || exit 1; \
|
||||
set -x; \
|
||||
mv dist/pychm*.egg ${librcldir};\
|
||||
)
|
||||
rclpychm-clean:
|
||||
rm -rf python/pychm/build
|
||||
rm -r python/pychm/dist/*
|
||||
|
||||
if MAKEPYTHON
|
||||
recollpython: librecoll.la
|
||||
(cd python/recoll; \
|
||||
set -x; \
|
||||
@ -546,7 +572,6 @@ recollpython: librecoll.la
|
||||
libdir=$(libdir) python$${v} setup.py build; \
|
||||
done \
|
||||
)
|
||||
install-exec-local: recollpython-install
|
||||
recollpython-install:
|
||||
(cd python/recoll; \
|
||||
if test -f /etc/debian_version ; then \
|
||||
@ -558,7 +583,6 @@ recollpython-install:
|
||||
--prefix=${prefix} --root=$${DESTDIR:-/} $${OPTSFORPYTHON}; \
|
||||
done; \
|
||||
)
|
||||
clean-local: recollpython-clean
|
||||
recollpython-clean:
|
||||
rm -rf python/recoll/build
|
||||
rm -rf python/recoll/__pycache__
|
||||
|
||||
@ -523,5 +523,6 @@ AC_SUBST(RCLLIBVERSION)
|
||||
AC_CONFIG_FILES(Makefile)
|
||||
AC_CONFIG_FILES(common/rclversion.h)
|
||||
AC_CONFIG_FILES(python/recoll/setup.py)
|
||||
AC_CONFIG_FILES(python/pychm/setup.py)
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
"""Extract Html files from a Microsoft Compiled Html Help file (.chm)
|
||||
Needs at least python 2.2 for HTMLParser (chmlib needs 2.2 too)"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
# Note: this is not converted to Py3, libchm does not have a
|
||||
# Py3 wrapper at this point (2018-03)
|
||||
|
||||
rclchm_html_mtype = "text/html"
|
||||
|
||||
import sys
|
||||
@ -18,16 +15,32 @@ if PY3:
|
||||
from urllib.parse import unquote as urllib_unquote
|
||||
from urllib.parse import urlparse as urlparse_urlparse
|
||||
from html.parser import HTMLParser
|
||||
chmpackname = 'pychm3.egg'
|
||||
else:
|
||||
from urlparse import urlparse as urlparse_urlparse
|
||||
from urllib import unquote as urllib_unquote
|
||||
from HTMLParser import HTMLParser
|
||||
|
||||
chmpackname = 'pychm2.egg'
|
||||
|
||||
import subprocess
|
||||
|
||||
import rclconfig
|
||||
import rclexecm
|
||||
|
||||
# pychm has no official port to Python3, hence no package in the
|
||||
# standard place. Recoll bundles a python3 port which we install out
|
||||
# of the standard python places. Look for it:
|
||||
# sys.path[0] is for MSW, where we install the egg in the filters
|
||||
# directory? TBD for now
|
||||
try:
|
||||
# First try the system version if any
|
||||
from chm import chm,chmlib
|
||||
except:
|
||||
for d in ('sys.path[0]', '/usr/lib/recoll', '/usr/local/lib/recoll'):
|
||||
p = os.path.join(d, chmpackname)
|
||||
if os.path.exists(p):
|
||||
sys.path.append(p)
|
||||
break
|
||||
try:
|
||||
from chm import chm,chmlib
|
||||
except:
|
||||
|
||||
28
src/python/pychm/AUTHORS
Normal file
28
src/python/pychm/AUTHORS
Normal file
@ -0,0 +1,28 @@
|
||||
Author
|
||||
------
|
||||
|
||||
Rubens Ramos <rubensr@users.sourceforge.net>
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
Mikhail Gusarov <dottedmag@dottedmag.net>
|
||||
|
||||
Python3 port minor changes
|
||||
--------------------------
|
||||
|
||||
Jean-Francois Dockes <jf@dockes.org>
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
|
||||
This work would not have been possible without the existence of chmlib,
|
||||
developed by Jed Wing, and a lot of the python code used to parse the contents
|
||||
tree and to decode the index files was heavily based on the code implemented by
|
||||
Razvan Cojocaru <razvanco@gmx.net> for the xCHM viewer.
|
||||
|
||||
Bug reports
|
||||
-----------
|
||||
|
||||
can3p, Chang (changshu), Hristo Iliev, Carlos Liu, Torsten Marek, Dmitri
|
||||
(nebraskin), Fredrik de Vibe, Glenn Washburn
|
||||
281
src/python/pychm/COPYING
Normal file
281
src/python/pychm/COPYING
Normal file
@ -0,0 +1,281 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
2
src/python/pychm/MANIFEST.in
Normal file
2
src/python/pychm/MANIFEST.in
Normal file
@ -0,0 +1,2 @@
|
||||
include COPYING
|
||||
include chm/swig_chm.i
|
||||
11
src/python/pychm/README-RECOLL.txt
Normal file
11
src/python/pychm/README-RECOLL.txt
Normal file
@ -0,0 +1,11 @@
|
||||
May 2018:
|
||||
|
||||
pychm has no python3 version. The pull request I submitted for the port is
|
||||
sitting there, and so is the Debian bug.
|
||||
|
||||
https://github.com/dottedmag/pychm/pull/5
|
||||
|
||||
Which is why Recoll bundles pychm, enhanced for Python3, for now. The
|
||||
source repo is here:
|
||||
|
||||
https://github.com/medoc92/pychm
|
||||
32
src/python/pychm/chm/__init__.py
Normal file
32
src/python/pychm/chm/__init__.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright (C) 2003-2006 Rubens Ramos <rubensr@users.sourceforge.net>
|
||||
#
|
||||
# pychm is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program 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. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; see the file COPYING. If not,
|
||||
# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
|
||||
'''
|
||||
chm - A package to manipulate CHM files
|
||||
|
||||
The chm package provides four modules: chm, chmlib, extra and
|
||||
_chmlib. _chmlib and chmlib are very low level libraries generated
|
||||
from SWIG interface files, and are simple wrappers around the API
|
||||
defined by the C library chmlib.
|
||||
The extra module adds full-text search support.
|
||||
the chm module provides some higher level classes to simplify
|
||||
access to the CHM files information.
|
||||
'''
|
||||
__all__ = ["chm", "chmlib", "_chmlib", "extra"]
|
||||
__version__ = "0.8.4.1+git"
|
||||
__revision__ = "$Id$"
|
||||
502
src/python/pychm/chm/chm.py
Normal file
502
src/python/pychm/chm/chm.py
Normal file
@ -0,0 +1,502 @@
|
||||
# Copyright (C) 2003-2006 Rubens Ramos <rubensr@users.sourceforge.net>
|
||||
#
|
||||
# Based on code by:
|
||||
# Copyright (C) 2003 Razvan Cojocaru <razvanco@gmx.net>
|
||||
#
|
||||
# pychm is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License as
|
||||
# published by the Free Software Foundation; either version 2 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program 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. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; see the file COPYING. If not,
|
||||
# write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
# Boston, MA 02111-1307, USA
|
||||
|
||||
'''
|
||||
chm - A high-level front end for the chmlib python module.
|
||||
|
||||
The chm module provides high level access to the functionality
|
||||
included in chmlib. It encapsulates functions in the CHMFile class, and
|
||||
provides some additional features, such as the ability to obtain
|
||||
the contents tree of a CHM archive.
|
||||
|
||||
'''
|
||||
|
||||
from . import chmlib
|
||||
from . import extra
|
||||
import array
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
charset_table = {
|
||||
0: 'iso8859_1', # ANSI_CHARSET
|
||||
238: 'iso8859_2', # EASTEUROPE_CHARSET
|
||||
178: 'iso8859_6', # ARABIC_CHARSET
|
||||
161: 'iso8859_7', # GREEK_CHARSET
|
||||
177: 'iso8859_8', # HEBREW_CHARSET
|
||||
162: 'iso8859_9', # TURKISH_CHARSET
|
||||
222: 'iso8859_11', # THAI_CHARSET - hmm not in python 2.2...
|
||||
186: 'iso8859_13', # BALTIC_CHARSET
|
||||
204: 'cp1251', # RUSSIAN_CHARSET
|
||||
255: 'cp437', # OEM_CHARSET
|
||||
128: 'cp932', # SHIFTJIS_CHARSET
|
||||
134: 'cp936', # GB2312_CHARSET
|
||||
129: 'cp949', # HANGUL_CHARSET
|
||||
136: 'cp950', # CHINESEBIG5_CHARSET
|
||||
1: None, # DEFAULT_CHARSET
|
||||
2: None, # SYMBOL_CHARSET
|
||||
130: None, # JOHAB_CHARSET
|
||||
163: None, # VIETNAMESE_CHARSET
|
||||
77: None, # MAC_CHARSET
|
||||
}
|
||||
|
||||
locale_table = {
|
||||
0x0436: ('iso8859_1', "Afrikaans", "Western Europe & US"),
|
||||
0x041c: ('iso8859_2', "Albanian", "Central Europe"),
|
||||
0x0401: ('iso8859_6', "Arabic_Saudi_Arabia", "Arabic"),
|
||||
0x0801: ('iso8859_6', "Arabic_Iraq", "Arabic"),
|
||||
0x0c01: ('iso8859_6', "Arabic_Egypt", "Arabic"),
|
||||
0x1001: ('iso8859_6', "Arabic_Libya", "Arabic"),
|
||||
0x1401: ('iso8859_6', "Arabic_Algeria", "Arabic"),
|
||||
0x1801: ('iso8859_6', "Arabic_Morocco", "Arabic"),
|
||||
0x1c01: ('iso8859_6', "Arabic_Tunisia", "Arabic"),
|
||||
0x2001: ('iso8859_6', "Arabic_Oman", "Arabic"),
|
||||
0x2401: ('iso8859_6', "Arabic_Yemen", "Arabic"),
|
||||
0x2801: ('iso8859_6', "Arabic_Syria", "Arabic"),
|
||||
0x2c01: ('iso8859_6', "Arabic_Jordan", "Arabic"),
|
||||
0x3001: ('iso8859_6', "Arabic_Lebanon", "Arabic"),
|
||||
0x3401: ('iso8859_6', "Arabic_Kuwait", "Arabic"),
|
||||
0x3801: ('iso8859_6', "Arabic_UAE", "Arabic"),
|
||||
0x3c01: ('iso8859_6', "Arabic_Bahrain", "Arabic"),
|
||||
0x4001: ('iso8859_6', "Arabic_Qatar", "Arabic"),
|
||||
0x042b: (None, "Armenian", "Armenian"),
|
||||
0x042c: ('iso8859_9', "Azeri_Latin", "Turkish"),
|
||||
0x082c: ('cp1251', "Azeri_Cyrillic", "Cyrillic"),
|
||||
0x042d: ('iso8859_1', "Basque", "Western Europe & US"),
|
||||
0x0423: ('cp1251', "Belarusian", "Cyrillic"),
|
||||
0x0402: ('cp1251', "Bulgarian", "Cyrillic"),
|
||||
0x0403: ('iso8859_1', "Catalan", "Western Europe & US"),
|
||||
0x0404: ('cp950', "Chinese_Taiwan", "Traditional Chinese"),
|
||||
0x0804: ('cp936', "Chinese_PRC", "Simplified Chinese"),
|
||||
0x0c04: ('cp950', "Chinese_Hong_Kong", "Traditional Chinese"),
|
||||
0x1004: ('cp936', "Chinese_Singapore", "Simplified Chinese"),
|
||||
0x1404: ('cp950', "Chinese_Macau", "Traditional Chinese"),
|
||||
0x041a: ('iso8859_2', "Croatian", "Central Europe"),
|
||||
0x0405: ('iso8859_2', "Czech", "Central Europe"),
|
||||
0x0406: ('iso8859_1', "Danish", "Western Europe & US"),
|
||||
0x0413: ('iso8859_1', "Dutch_Standard", "Western Europe & US"),
|
||||
0x0813: ('iso8859_1', "Dutch_Belgian", "Western Europe & US"),
|
||||
0x0409: ('iso8859_1', "English_United_States", "Western Europe & US"),
|
||||
0x0809: ('iso8859_1', "English_United_Kingdom", "Western Europe & US"),
|
||||
0x0c09: ('iso8859_1', "English_Australian", "Western Europe & US"),
|
||||
0x1009: ('iso8859_1', "English_Canadian", "Western Europe & US"),
|
||||
0x1409: ('iso8859_1', "English_New_Zealand", "Western Europe & US"),
|
||||
0x1809: ('iso8859_1', "English_Irish", "Western Europe & US"),
|
||||
0x1c09: ('iso8859_1', "English_South_Africa", "Western Europe & US"),
|
||||
0x2009: ('iso8859_1', "English_Jamaica", "Western Europe & US"),
|
||||
0x2409: ('iso8859_1', "English_Caribbean", "Western Europe & US"),
|
||||
0x2809: ('iso8859_1', "English_Belize", "Western Europe & US"),
|
||||
0x2c09: ('iso8859_1', "English_Trinidad", "Western Europe & US"),
|
||||
0x3009: ('iso8859_1', "English_Zimbabwe", "Western Europe & US"),
|
||||
0x3409: ('iso8859_1', "English_Philippines", "Western Europe & US"),
|
||||
0x0425: ('iso8859_13', "Estonian", "Baltic",),
|
||||
0x0438: ('iso8859_1', "Faeroese", "Western Europe & US"),
|
||||
0x0429: ('iso8859_6', "Farsi", "Arabic"),
|
||||
0x040b: ('iso8859_1', "Finnish", "Western Europe & US"),
|
||||
0x040c: ('iso8859_1', "French_Standard", "Western Europe & US"),
|
||||
0x080c: ('iso8859_1', "French_Belgian", "Western Europe & US"),
|
||||
0x0c0c: ('iso8859_1', "French_Canadian", "Western Europe & US"),
|
||||
0x100c: ('iso8859_1', "French_Swiss", "Western Europe & US"),
|
||||
0x140c: ('iso8859_1', "French_Luxembourg", "Western Europe & US"),
|
||||
0x180c: ('iso8859_1', "French_Monaco", "Western Europe & US"),
|
||||
0x0437: (None, "Georgian", "Georgian"),
|
||||
0x0407: ('iso8859_1', "German_Standard", "Western Europe & US"),
|
||||
0x0807: ('iso8859_1', "German_Swiss", "Western Europe & US"),
|
||||
0x0c07: ('iso8859_1', "German_Austrian", "Western Europe & US"),
|
||||
0x1007: ('iso8859_1', "German_Luxembourg", "Western Europe & US"),
|
||||
0x1407: ('iso8859_1', "German_Liechtenstein", "Western Europe & US"),
|
||||
0x0408: ('iso8859_7', "Greek", "Greek"),
|
||||
0x040d: ('iso8859_8', "Hebrew", "Hebrew"),
|
||||
0x0439: (None, "Hindi", "Indic"),
|
||||
0x040e: ('iso8859_2', "Hungarian", "Central Europe"),
|
||||
0x040f: ('iso8859_1', "Icelandic", "Western Europe & US"),
|
||||
0x0421: ('iso8859_1', "Indonesian", "Western Europe & US"),
|
||||
0x0410: ('iso8859_1', "Italian_Standard", "Western Europe & US"),
|
||||
0x0810: ('iso8859_1', "Italian_Swiss", "Western Europe & US"),
|
||||
0x0411: ('cp932', "Japanese", "Japanese"),
|
||||
0x043f: ('cp1251', "Kazakh", "Cyrillic"),
|
||||
0x0457: (None, "Konkani", "Indic"),
|
||||
0x0412: ('cp949', "Korean", "Korean"),
|
||||
0x0426: ('iso8859_13', "Latvian", "Baltic",),
|
||||
0x0427: ('iso8859_13', "Lithuanian", "Baltic",),
|
||||
0x042f: ('cp1251', "Macedonian", "Cyrillic"),
|
||||
0x043e: ('iso8859_1', "Malay_Malaysia", "Western Europe & US"),
|
||||
0x083e: ('iso8859_1', "Malay_Brunei_Darussalam", "Western Europe & US"),
|
||||
0x044e: (None, "Marathi", "Indic"),
|
||||
0x0414: ('iso8859_1', "Norwegian_Bokmal", "Western Europe & US"),
|
||||
0x0814: ('iso8859_1', "Norwegian_Nynorsk", "Western Europe & US"),
|
||||
0x0415: ('iso8859_2', "Polish", "Central Europe"),
|
||||
0x0416: ('iso8859_1', "Portuguese_Brazilian", "Western Europe & US"),
|
||||
0x0816: ('iso8859_1', "Portuguese_Standard", "Western Europe & US"),
|
||||
0x0418: ('iso8859_2', "Romanian", "Central Europe"),
|
||||
0x0419: ('cp1251', "Russian", "Cyrillic"),
|
||||
0x044f: (None, "Sanskrit", "Indic"),
|
||||
0x081a: ('iso8859_2', "Serbian_Latin", "Central Europe"),
|
||||
0x0c1a: ('cp1251', "Serbian_Cyrillic", "Cyrillic"),
|
||||
0x041b: ('iso8859_2', "Slovak", "Central Europe"),
|
||||
0x0424: ('iso8859_2', "Slovenian", "Central Europe"),
|
||||
0x040a: ('iso8859_1', "Spanish_Trad_Sort", "Western Europe & US"),
|
||||
0x080a: ('iso8859_1', "Spanish_Mexican", "Western Europe & US"),
|
||||
0x0c0a: ('iso8859_1', "Spanish_Modern_Sort", "Western Europe & US"),
|
||||
0x100a: ('iso8859_1', "Spanish_Guatemala", "Western Europe & US"),
|
||||
0x140a: ('iso8859_1', "Spanish_Costa_Rica", "Western Europe & US"),
|
||||
0x180a: ('iso8859_1', "Spanish_Panama", "Western Europe & US"),
|
||||
0x1c0a: ('iso8859_1', "Spanish_Dominican_Repub", "Western Europe & US"),
|
||||
0x200a: ('iso8859_1', "Spanish_Venezuela", "Western Europe & US"),
|
||||
0x240a: ('iso8859_1', "Spanish_Colombia", "Western Europe & US"),
|
||||
0x280a: ('iso8859_1', "Spanish_Peru", "Western Europe & US"),
|
||||
0x2c0a: ('iso8859_1', "Spanish_Argentina", "Western Europe & US"),
|
||||
0x300a: ('iso8859_1', "Spanish_Ecuador", "Western Europe & US"),
|
||||
0x340a: ('iso8859_1', "Spanish_Chile", "Western Europe & US"),
|
||||
0x380a: ('iso8859_1', "Spanish_Uruguay", "Western Europe & US"),
|
||||
0x3c0a: ('iso8859_1', "Spanish_Paraguay", "Western Europe & US"),
|
||||
0x400a: ('iso8859_1', "Spanish_Bolivia", "Western Europe & US"),
|
||||
0x440a: ('iso8859_1', "Spanish_El_Salvador", "Western Europe & US"),
|
||||
0x480a: ('iso8859_1', "Spanish_Honduras", "Western Europe & US"),
|
||||
0x4c0a: ('iso8859_1', "Spanish_Nicaragua", "Western Europe & US"),
|
||||
0x500a: ('iso8859_1', "Spanish_Puerto_Rico", "Western Europe & US"),
|
||||
0x0441: ('iso8859_1', "Swahili", "Western Europe & US"),
|
||||
0x041d: ('iso8859_1', "Swedish", "Western Europe & US"),
|
||||
0x081d: ('iso8859_1', "Swedish_Finland", "Western Europe & US"),
|
||||
0x0449: (None, "Tamil", "Indic"),
|
||||
0x0444: ('cp1251', "Tatar", "Cyrillic"),
|
||||
0x041e: ('iso8859_11', "Thai", "Thai"),
|
||||
0x041f: ('iso8859_9', "Turkish", "Turkish"),
|
||||
0x0422: ('cp1251', "Ukrainian", "Cyrillic"),
|
||||
0x0420: ('iso8859_6', "Urdu", "Arabic"),
|
||||
0x0443: ('iso8859_9', "Uzbek_Latin", "Turkish"),
|
||||
0x0843: ('cp1251', "Uzbek_Cyrillic", "Cyrillic"),
|
||||
0x042a: (None, "Vietnamese", "Vietnamese")
|
||||
}
|
||||
|
||||
|
||||
class CHMFile:
|
||||
"A class to manage access to CHM files."
|
||||
filename = ""
|
||||
file = None
|
||||
title = ""
|
||||
home = "/"
|
||||
index = None
|
||||
topics = None
|
||||
encoding = None
|
||||
lcid = None
|
||||
binaryindex = None
|
||||
|
||||
def __init__(self):
|
||||
self.searchable = 0
|
||||
|
||||
def LoadCHM(self, archiveName):
|
||||
'''Loads a CHM archive.
|
||||
This function will also call GetArchiveInfo to obtain information
|
||||
such as the index file name and the topics file. It returns 1 on
|
||||
success, and 0 if it fails.
|
||||
'''
|
||||
if self.filename is not None:
|
||||
self.CloseCHM()
|
||||
|
||||
self.file = chmlib.chm_open(archiveName)
|
||||
if self.file is None:
|
||||
return 0
|
||||
|
||||
self.filename = archiveName
|
||||
self.GetArchiveInfo()
|
||||
|
||||
return 1
|
||||
|
||||
def CloseCHM(self):
|
||||
'''Closes the CHM archive.
|
||||
This function will close the CHM file, if it is open. All variables
|
||||
are also reset.
|
||||
'''
|
||||
if self.filename is not None:
|
||||
chmlib.chm_close(self.file)
|
||||
self.file = None
|
||||
self.filename = ''
|
||||
self.title = ""
|
||||
self.home = "/"
|
||||
self.index = None
|
||||
self.topics = None
|
||||
self.encoding = None
|
||||
|
||||
def GetArchiveInfo(self):
|
||||
'''Obtains information on CHM archive.
|
||||
This function checks the /#SYSTEM file inside the CHM archive to
|
||||
obtain the index, home page, topics, encoding and title. It is called
|
||||
from LoadCHM.
|
||||
'''
|
||||
|
||||
self.searchable = extra.is_searchable(self.file)
|
||||
self.lcid = None
|
||||
|
||||
result, ui = chmlib.chm_resolve_object(self.file, b'/#SYSTEM')
|
||||
if (result != chmlib.CHM_RESOLVE_SUCCESS):
|
||||
sys.stderr.write('GetArchiveInfo: #SYSTEM does not exist\n')
|
||||
return 0
|
||||
|
||||
size, text = chmlib.chm_retrieve_object(self.file, ui, 4, ui.length)
|
||||
if (size == 0):
|
||||
sys.stderr.write('GetArchiveInfo: file size = 0\n')
|
||||
return 0
|
||||
|
||||
buff = array.array('B', text)
|
||||
|
||||
index = 0
|
||||
while (index < size):
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
|
||||
if (cursor == 0):
|
||||
index += 2
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
index += 2
|
||||
self.topics = b'/' + text[index:index+cursor-1]
|
||||
elif (cursor == 1):
|
||||
index += 2
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
index += 2
|
||||
self.index = b'/' + text[index:index+cursor-1]
|
||||
elif (cursor == 2):
|
||||
index += 2
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
index += 2
|
||||
self.home = b'/' + text[index:index+cursor-1]
|
||||
elif (cursor == 3):
|
||||
index += 2
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
index += 2
|
||||
self.title = text[index:index+cursor-1]
|
||||
elif (cursor == 4):
|
||||
index += 2
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
index += 2
|
||||
self.lcid = buff[index] + (buff[index+1] * 256)
|
||||
elif (cursor == 6):
|
||||
index += 2
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
index += 2
|
||||
tmp = text[index:index+cursor-1]
|
||||
if not self.topics:
|
||||
tmp1 = b'/' + tmp + b'.hhc'
|
||||
tmp2 = b'/' + tmp + b'.hhk'
|
||||
res1, ui1 = chmlib.chm_resolve_object(self.file, tmp1)
|
||||
res2, ui2 = chmlib.chm_resolve_object(self.file, tmp2)
|
||||
if not self.topics and res1 == chmlib.CHM_RESOLVE_SUCCESS:
|
||||
self.topics = b'/' + tmp + b'.hhc'
|
||||
if not self.index and res2 == chmlib.CHM_RESOLVE_SUCCESS:
|
||||
self.index = b'/' + tmp + b'.hhk'
|
||||
elif (cursor == 16):
|
||||
index += 2
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
index += 2
|
||||
self.encoding = text[index:index+cursor-1]
|
||||
else:
|
||||
index += 2
|
||||
cursor = buff[index] + (buff[index+1] * 256)
|
||||
index += 2
|
||||
index += cursor
|
||||
|
||||
self.GetWindowsInfo()
|
||||
|
||||
if not self.lcid:
|
||||
self.lcid = extra.get_lcid(self.file)
|
||||
|
||||
return 1
|
||||
|
||||
def GetTopicsTree(self):
|
||||
'''Reads and returns the topics tree.
|
||||
This auxiliary function reads and returns the topics tree file
|
||||
contents for the CHM archive.
|
||||
'''
|
||||
if self.topics is None:
|
||||
return None
|
||||
|
||||
if self.topics:
|
||||
res, ui = chmlib.chm_resolve_object(self.file, self.topics)
|
||||
if (res != chmlib.CHM_RESOLVE_SUCCESS):
|
||||
return None
|
||||
|
||||
size, text = chmlib.chm_retrieve_object(self.file, ui, 0, ui.length)
|
||||
if (size == 0):
|
||||
sys.stderr.write('GetTopicsTree: file size = 0\n')
|
||||
return None
|
||||
return text
|
||||
|
||||
def GetIndex(self):
|
||||
'''Reads and returns the index tree.
|
||||
This auxiliary function reads and returns the index tree file
|
||||
contents for the CHM archive.
|
||||
'''
|
||||
if self.index is None:
|
||||
return None
|
||||
|
||||
if self.index:
|
||||
res, ui = chmlib.chm_resolve_object(self.file, self.index)
|
||||
if (res != chmlib.CHM_RESOLVE_SUCCESS):
|
||||
return None
|
||||
|
||||
size, text = chmlib.chm_retrieve_object(self.file, ui, 0, ui.length)
|
||||
if (size == 0):
|
||||
sys.stderr.write('GetIndex: file size = 0\n')
|
||||
return None
|
||||
return text
|
||||
|
||||
def ResolveObject(self, document):
|
||||
'''Tries to locate a document in the archive.
|
||||
This function tries to locate the document inside the archive. It
|
||||
returns a tuple where the first element is zero if the function
|
||||
was successful, and the second is the UnitInfo for that document.
|
||||
The UnitInfo is used to retrieve the document contents
|
||||
'''
|
||||
if self.file:
|
||||
# path = os.path.abspath(document) # wtf?? the index contents
|
||||
# are independant of the os !
|
||||
path = document
|
||||
return chmlib.chm_resolve_object(self.file, path)
|
||||
else:
|
||||
return (1, None)
|
||||
|
||||
def RetrieveObject(self, ui, start=-1, length=-1):
|
||||
'''Retrieves the contents of a document.
|
||||
This function takes a UnitInfo and two optional arguments, the first
|
||||
being the start address and the second is the length. These define
|
||||
the amount of data to be read from the archive.
|
||||
'''
|
||||
if self.file and ui:
|
||||
if length == -1:
|
||||
len = ui.length
|
||||
else:
|
||||
len = length
|
||||
if start == -1:
|
||||
st = 0
|
||||
else:
|
||||
st = long(start)
|
||||
return chmlib.chm_retrieve_object(self.file, ui, st, len)
|
||||
else:
|
||||
return (0, '')
|
||||
|
||||
def Search(self, text, wholewords=0, titleonly=0):
|
||||
'''Performs full-text search on the archive.
|
||||
The first parameter is the word to look for, the second
|
||||
indicates if the search should be for whole words only, and
|
||||
the third parameter indicates if the search should be
|
||||
restricted to page titles.
|
||||
This method will return a tuple, the first item
|
||||
indicating if the search results were partial, and the second
|
||||
item being a dictionary containing the results.'''
|
||||
if text and text != '' and self.file:
|
||||
return extra.search(self.file, text, wholewords, titleonly)
|
||||
else:
|
||||
return None
|
||||
|
||||
def IsSearchable(self):
|
||||
'''Indicates if the full-text search is available for this
|
||||
archive - this flag is updated when GetArchiveInfo is called'''
|
||||
return self.searchable
|
||||
|
||||
def GetEncoding(self):
|
||||
'''Returns a string that can be used with the codecs python package
|
||||
to encode or decode the files in the chm archive. If an error is
|
||||
found, or if it is not possible to find the encoding, None is
|
||||
returned.'''
|
||||
if self.encoding:
|
||||
vals = self.encoding.split(b',')
|
||||
if len(vals) > 2:
|
||||
try:
|
||||
return charset_table[int(vals[2])]
|
||||
except KeyError:
|
||||
pass
|
||||
return None
|
||||
|
||||
def GetLCID(self):
|
||||
'''Returns the archive Locale ID'''
|
||||
if self.lcid in locale_table:
|
||||
return locale_table[self.lcid]
|
||||
else:
|
||||
return None
|
||||
|
||||
def GetDWORD(self, buff, idx=0):
|
||||
'''Internal method.
|
||||
Reads a double word (4 bytes) from a buffer.
|
||||
'''
|
||||
result = buff[idx] + (buff[idx+1] << 8) + (buff[idx+2] << 16) + \
|
||||
(buff[idx+3] << 24)
|
||||
|
||||
if result == 0xFFFFFFFF:
|
||||
result = 0
|
||||
|
||||
return result
|
||||
|
||||
def GetString(self, text, idx):
|
||||
'''Internal method.
|
||||
Retrieves a string from the #STRINGS buffer.
|
||||
'''
|
||||
next = text.find(b'\x00', idx)
|
||||
chunk = text[idx:next]
|
||||
return chunk
|
||||
|
||||
def GetWindowsInfo(self):
|
||||
'''Gets information from the #WINDOWS file.
|
||||
Checks the #WINDOWS file to see if it has any info that was
|
||||
not found in #SYSTEM (topics, index or default page.
|
||||
'''
|
||||
result, ui = chmlib.chm_resolve_object(self.file, b'/#WINDOWS')
|
||||
if (result != chmlib.CHM_RESOLVE_SUCCESS):
|
||||
return -1
|
||||
|
||||
size, text = chmlib.chm_retrieve_object(self.file, ui, 0, 8)
|
||||
if (size < 8):
|
||||
return -2
|
||||
|
||||
buff = array.array('B', text)
|
||||
num_entries = self.GetDWORD(buff, 0)
|
||||
entry_size = self.GetDWORD(buff, 4)
|
||||
|
||||
if num_entries < 1:
|
||||
return -3
|
||||
|
||||
size, text = chmlib.chm_retrieve_object(self.file, ui, 8, entry_size)
|
||||
if (size < entry_size):
|
||||
return -4
|
||||
|
||||
buff = array.array('B', text)
|
||||
toc_index = self.GetDWORD(buff, 0x60)
|
||||
idx_index = self.GetDWORD(buff, 0x64)
|
||||
dft_index = self.GetDWORD(buff, 0x68)
|
||||
|
||||
result, ui = chmlib.chm_resolve_object(self.file, b'/#STRINGS')
|
||||
if (result != chmlib.CHM_RESOLVE_SUCCESS):
|
||||
return -5
|
||||
|
||||
size, text = chmlib.chm_retrieve_object(self.file, ui, 0, ui.length)
|
||||
if (size == 0):
|
||||
return -6
|
||||
|
||||
if (not self.topics):
|
||||
self.topics = self.GetString(text, toc_index)
|
||||
if not self.topics.startswith(b"/"):
|
||||
self.topics = b"/" + self.topics
|
||||
|
||||
if (not self.index):
|
||||
self.index = self.GetString(text, idx_index)
|
||||
if not self.index.startswith(b"/"):
|
||||
self.index = b"/" + self.index
|
||||
|
||||
if (dft_index != 0):
|
||||
self.home = self.GetString(text, dft_index)
|
||||
if not self.home.startswith(b"/"):
|
||||
self.home = b"/" + self.home
|
||||
180
src/python/pychm/chm/chmlib.py
Normal file
180
src/python/pychm/chm/chmlib.py
Normal file
@ -0,0 +1,180 @@
|
||||
# This file was automatically generated by SWIG (http://www.swig.org).
|
||||
# Version 3.0.10
|
||||
#
|
||||
# Do not make changes to this file unless you know what you are doing--modify
|
||||
# the SWIG interface file instead.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
from sys import version_info as _swig_python_version_info
|
||||
if _swig_python_version_info >= (2, 7, 0):
|
||||
def swig_import_helper():
|
||||
import importlib
|
||||
pkg = __name__.rpartition('.')[0]
|
||||
mname = '.'.join((pkg, '_chmlib')).lstrip('.')
|
||||
try:
|
||||
return importlib.import_module(mname)
|
||||
except ImportError:
|
||||
return importlib.import_module('_chmlib')
|
||||
_chmlib = swig_import_helper()
|
||||
del swig_import_helper
|
||||
elif _swig_python_version_info >= (2, 6, 0):
|
||||
def swig_import_helper():
|
||||
from os.path import dirname
|
||||
import imp
|
||||
fp = None
|
||||
try:
|
||||
fp, pathname, description = imp.find_module('_chmlib', [dirname(__file__)])
|
||||
except ImportError:
|
||||
import _chmlib
|
||||
return _chmlib
|
||||
if fp is not None:
|
||||
try:
|
||||
_mod = imp.load_module('_chmlib', fp, pathname, description)
|
||||
finally:
|
||||
fp.close()
|
||||
return _mod
|
||||
_chmlib = swig_import_helper()
|
||||
del swig_import_helper
|
||||
else:
|
||||
import _chmlib
|
||||
del _swig_python_version_info
|
||||
try:
|
||||
_swig_property = property
|
||||
except NameError:
|
||||
pass # Python < 2.2 doesn't have 'property'.
|
||||
|
||||
try:
|
||||
import builtins as __builtin__
|
||||
except ImportError:
|
||||
import __builtin__
|
||||
|
||||
def _swig_setattr_nondynamic(self, class_type, name, value, static=1):
|
||||
if (name == "thisown"):
|
||||
return self.this.own(value)
|
||||
if (name == "this"):
|
||||
if type(value).__name__ == 'SwigPyObject':
|
||||
self.__dict__[name] = value
|
||||
return
|
||||
method = class_type.__swig_setmethods__.get(name, None)
|
||||
if method:
|
||||
return method(self, value)
|
||||
if (not static):
|
||||
if _newclass:
|
||||
object.__setattr__(self, name, value)
|
||||
else:
|
||||
self.__dict__[name] = value
|
||||
else:
|
||||
raise AttributeError("You cannot add attributes to %s" % self)
|
||||
|
||||
|
||||
def _swig_setattr(self, class_type, name, value):
|
||||
return _swig_setattr_nondynamic(self, class_type, name, value, 0)
|
||||
|
||||
|
||||
def _swig_getattr(self, class_type, name):
|
||||
if (name == "thisown"):
|
||||
return self.this.own()
|
||||
method = class_type.__swig_getmethods__.get(name, None)
|
||||
if method:
|
||||
return method(self)
|
||||
raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name))
|
||||
|
||||
|
||||
def _swig_repr(self):
|
||||
try:
|
||||
strthis = "proxy of " + self.this.__repr__()
|
||||
except __builtin__.Exception:
|
||||
strthis = ""
|
||||
return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)
|
||||
|
||||
try:
|
||||
_object = object
|
||||
_newclass = 1
|
||||
except __builtin__.Exception:
|
||||
class _object:
|
||||
pass
|
||||
_newclass = 0
|
||||
|
||||
CHM_UNCOMPRESSED = _chmlib.CHM_UNCOMPRESSED
|
||||
CHM_COMPRESSED = _chmlib.CHM_COMPRESSED
|
||||
CHM_MAX_PATHLEN = _chmlib.CHM_MAX_PATHLEN
|
||||
class chmUnitInfo(_object):
|
||||
__swig_setmethods__ = {}
|
||||
__setattr__ = lambda self, name, value: _swig_setattr(self, chmUnitInfo, name, value)
|
||||
__swig_getmethods__ = {}
|
||||
__getattr__ = lambda self, name: _swig_getattr(self, chmUnitInfo, name)
|
||||
__repr__ = _swig_repr
|
||||
__swig_setmethods__["start"] = _chmlib.chmUnitInfo_start_set
|
||||
__swig_getmethods__["start"] = _chmlib.chmUnitInfo_start_get
|
||||
if _newclass:
|
||||
start = _swig_property(_chmlib.chmUnitInfo_start_get, _chmlib.chmUnitInfo_start_set)
|
||||
__swig_setmethods__["length"] = _chmlib.chmUnitInfo_length_set
|
||||
__swig_getmethods__["length"] = _chmlib.chmUnitInfo_length_get
|
||||
if _newclass:
|
||||
length = _swig_property(_chmlib.chmUnitInfo_length_get, _chmlib.chmUnitInfo_length_set)
|
||||
__swig_setmethods__["space"] = _chmlib.chmUnitInfo_space_set
|
||||
__swig_getmethods__["space"] = _chmlib.chmUnitInfo_space_get
|
||||
if _newclass:
|
||||
space = _swig_property(_chmlib.chmUnitInfo_space_get, _chmlib.chmUnitInfo_space_set)
|
||||
__swig_setmethods__["path"] = _chmlib.chmUnitInfo_path_set
|
||||
__swig_getmethods__["path"] = _chmlib.chmUnitInfo_path_get
|
||||
if _newclass:
|
||||
path = _swig_property(_chmlib.chmUnitInfo_path_get, _chmlib.chmUnitInfo_path_set)
|
||||
|
||||
def __init__(self):
|
||||
this = _chmlib.new_chmUnitInfo()
|
||||
try:
|
||||
self.this.append(this)
|
||||
except __builtin__.Exception:
|
||||
self.this = this
|
||||
__swig_destroy__ = _chmlib.delete_chmUnitInfo
|
||||
__del__ = lambda self: None
|
||||
chmUnitInfo_swigregister = _chmlib.chmUnitInfo_swigregister
|
||||
chmUnitInfo_swigregister(chmUnitInfo)
|
||||
|
||||
|
||||
def chm_open(filename):
|
||||
return _chmlib.chm_open(filename)
|
||||
chm_open = _chmlib.chm_open
|
||||
|
||||
def chm_close(h):
|
||||
return _chmlib.chm_close(h)
|
||||
chm_close = _chmlib.chm_close
|
||||
CHM_PARAM_MAX_BLOCKS_CACHED = _chmlib.CHM_PARAM_MAX_BLOCKS_CACHED
|
||||
|
||||
def chm_set_param(h, paramType, paramVal):
|
||||
return _chmlib.chm_set_param(h, paramType, paramVal)
|
||||
chm_set_param = _chmlib.chm_set_param
|
||||
CHM_RESOLVE_SUCCESS = _chmlib.CHM_RESOLVE_SUCCESS
|
||||
CHM_RESOLVE_FAILURE = _chmlib.CHM_RESOLVE_FAILURE
|
||||
|
||||
def chm_resolve_object(h, objPath):
|
||||
return _chmlib.chm_resolve_object(h, objPath)
|
||||
chm_resolve_object = _chmlib.chm_resolve_object
|
||||
|
||||
def chm_retrieve_object(h, ui, addr, len):
|
||||
return _chmlib.chm_retrieve_object(h, ui, addr, len)
|
||||
chm_retrieve_object = _chmlib.chm_retrieve_object
|
||||
CHM_ENUMERATE_NORMAL = _chmlib.CHM_ENUMERATE_NORMAL
|
||||
CHM_ENUMERATE_META = _chmlib.CHM_ENUMERATE_META
|
||||
CHM_ENUMERATE_SPECIAL = _chmlib.CHM_ENUMERATE_SPECIAL
|
||||
CHM_ENUMERATE_FILES = _chmlib.CHM_ENUMERATE_FILES
|
||||
CHM_ENUMERATE_DIRS = _chmlib.CHM_ENUMERATE_DIRS
|
||||
CHM_ENUMERATE_ALL = _chmlib.CHM_ENUMERATE_ALL
|
||||
CHM_ENUMERATOR_FAILURE = _chmlib.CHM_ENUMERATOR_FAILURE
|
||||
CHM_ENUMERATOR_CONTINUE = _chmlib.CHM_ENUMERATOR_CONTINUE
|
||||
CHM_ENUMERATOR_SUCCESS = _chmlib.CHM_ENUMERATOR_SUCCESS
|
||||
|
||||
def chm_enumerate(h, what, e, context):
|
||||
return _chmlib.chm_enumerate(h, what, e, context)
|
||||
chm_enumerate = _chmlib.chm_enumerate
|
||||
|
||||
def chm_enumerate_dir(h, prefix, what, e, context):
|
||||
return _chmlib.chm_enumerate_dir(h, prefix, what, e, context)
|
||||
chm_enumerate_dir = _chmlib.chm_enumerate_dir
|
||||
# This file is compatible with both classic and new-style classes.
|
||||
|
||||
|
||||
803
src/python/pychm/chm/extra.c
Normal file
803
src/python/pychm/chm/extra.c
Normal file
@ -0,0 +1,803 @@
|
||||
/*
|
||||
* extra.c - full-text search support for pychm
|
||||
*
|
||||
* Copyright (C) 2004 Rubens Ramos <rubensr@users.sourceforge.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Author: Rubens Ramos <rubensr@users.sourceforge.net>
|
||||
*
|
||||
* Heavily based on work done by:
|
||||
* Pabs <pabs@zip.to> - chmdeco
|
||||
* Razvan Cojocaru <razvanco@gmx.net> - xCHM
|
||||
*
|
||||
*/
|
||||
|
||||
#include "chm_lib.h"
|
||||
#ifdef __PYTHON__
|
||||
#include "Python.h"
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define PyObject void
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
void *ptr;
|
||||
void *ty;
|
||||
int own;
|
||||
PyObject *next;
|
||||
#ifdef SWIGPYTHON_BUILTIN
|
||||
PyObject *dict;
|
||||
#endif
|
||||
} SwigPyObject;
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__)
|
||||
# if defined(_MSC_VER)
|
||||
# if defined(STATIC_LINKED)
|
||||
# define MODEXPORT(a) a
|
||||
# define MODIMPORT(a) extern a
|
||||
# else
|
||||
# define MODEXPORT(a) __declspec(dllexport) a
|
||||
# define MODIMPORT(a) extern a
|
||||
# endif
|
||||
#define uint64_t unsigned long long
|
||||
#define uint32_t unsigned int
|
||||
#define uint16_t unsigned short
|
||||
#define uint8_t unsigned char
|
||||
#define size_t int
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
# else
|
||||
# if defined(__BORLANDC__)
|
||||
# define MODEXPORT(a) a _export
|
||||
# define MODIMPORT(a) a _export
|
||||
# else
|
||||
# define MODEXPORT(a) a
|
||||
# define MODIMPORT(a) a
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
# define MODEXPORT(a) a
|
||||
# define MODIMPORT(a) a
|
||||
#include <inttypes.h>
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
#define FTS_HEADER_LEN 0x32
|
||||
#define TOPICS_ENTRY_LEN 16
|
||||
#define COMMON_BUF_LEN 1025
|
||||
|
||||
#define FREE(x) free (x); x = NULL
|
||||
|
||||
static uint16_t
|
||||
get_uint16 (uint8_t* b) {
|
||||
return b[0] |
|
||||
b[1]<<8;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
get_uint32 (uint8_t* b) {
|
||||
return b[0] |
|
||||
b[1]<<8 |
|
||||
b[2]<<16 |
|
||||
b[3]<<24;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
be_encint (unsigned char *buffer, size_t *length)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
int shift=0;
|
||||
*length = 0;
|
||||
|
||||
do {
|
||||
result |= ((*buffer) & 0x7f) << shift;
|
||||
shift += 7;
|
||||
*length = *length + 1;
|
||||
|
||||
} while (*(buffer++) & 0x80);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Finds the first unset bit in memory. Returns the number of set bits found.
|
||||
Returns -1 if the buffer runs out before we find an unset bit.
|
||||
*/
|
||||
static int
|
||||
ffus (unsigned char* byte, int* bit, size_t *length) {
|
||||
int bits = 0;
|
||||
*length = 0;
|
||||
|
||||
while(*byte & (1 << *bit)){
|
||||
if(*bit)
|
||||
--(*bit);
|
||||
else {
|
||||
++byte;
|
||||
++(*length);
|
||||
*bit = 7;
|
||||
}
|
||||
++bits;
|
||||
}
|
||||
|
||||
if(*bit)
|
||||
--(*bit);
|
||||
else {
|
||||
++(*length);
|
||||
*bit = 7;
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
sr_int(unsigned char* byte, int* bit,
|
||||
unsigned char s, unsigned char r, size_t *length)
|
||||
{
|
||||
uint64_t ret;
|
||||
unsigned char mask;
|
||||
int n, n_bits, num_bits, base, count;
|
||||
size_t fflen;
|
||||
|
||||
*length = 0;
|
||||
|
||||
if(!bit || *bit > 7 || s != 2)
|
||||
return ~(uint64_t)0;
|
||||
ret = 0;
|
||||
|
||||
count = ffus(byte, bit, &fflen);
|
||||
*length += fflen;
|
||||
byte += *length;
|
||||
|
||||
n_bits = n = r + (count ? count-1 : 0) ;
|
||||
|
||||
while (n > 0) {
|
||||
num_bits = n > *bit ? *bit : n-1;
|
||||
base = n > *bit ? 0 : *bit - (n-1);
|
||||
|
||||
switch (num_bits){
|
||||
case 0:
|
||||
mask = 1;
|
||||
break;
|
||||
case 1:
|
||||
mask = 3;
|
||||
break;
|
||||
case 2:
|
||||
mask = 7;
|
||||
break;
|
||||
case 3:
|
||||
mask = 0xf;
|
||||
break;
|
||||
case 4:
|
||||
mask = 0x1f;
|
||||
break;
|
||||
case 5:
|
||||
mask = 0x3f;
|
||||
break;
|
||||
case 6:
|
||||
mask = 0x7f;
|
||||
break;
|
||||
case 7:
|
||||
mask = 0xff;
|
||||
break;
|
||||
default:
|
||||
mask = 0xff;
|
||||
break;
|
||||
}
|
||||
|
||||
mask <<= base;
|
||||
ret = (ret << (num_bits+1)) |
|
||||
(uint64_t)((*byte & mask) >> base);
|
||||
|
||||
if( n > *bit ){
|
||||
++byte;
|
||||
++(*length);
|
||||
n -= *bit+1;
|
||||
*bit = 7;
|
||||
} else {
|
||||
*bit -= n;
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(count)
|
||||
ret |= (uint64_t)1 << n_bits;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t
|
||||
get_leaf_node_offset(struct chmFile *chmfile,
|
||||
const char *text,
|
||||
uint32_t initial_offset,
|
||||
uint32_t buff_size,
|
||||
uint16_t tree_depth,
|
||||
struct chmUnitInfo *ui)
|
||||
{
|
||||
unsigned char word_len;
|
||||
unsigned char pos;
|
||||
uint16_t free_space;
|
||||
char *wrd_buf;
|
||||
char *word = NULL;
|
||||
uint32_t test_offset = 0;
|
||||
uint32_t i = sizeof(uint16_t);
|
||||
unsigned char *buffer = malloc (buff_size);
|
||||
|
||||
if (NULL == buffer)
|
||||
return 0;
|
||||
|
||||
while (--tree_depth) {
|
||||
if (initial_offset == test_offset) {
|
||||
FREE(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
test_offset = initial_offset;
|
||||
if (chm_retrieve_object (chmfile, ui, buffer,
|
||||
initial_offset, buff_size) == 0) {
|
||||
FREE(buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
free_space = get_uint16 (buffer);
|
||||
|
||||
while (i < buff_size - free_space) {
|
||||
|
||||
word_len = *(buffer + i);
|
||||
pos = *(buffer + i + 1);
|
||||
|
||||
wrd_buf = malloc (word_len);
|
||||
memcpy (wrd_buf, buffer + i + 2, word_len - 1);
|
||||
wrd_buf[word_len - 1] = 0;
|
||||
|
||||
if (pos == 0) {
|
||||
FREE (word);
|
||||
word = (char *) strdup (wrd_buf);
|
||||
} else {
|
||||
word = realloc (word, word_len + pos + 1);
|
||||
strcpy (word + pos, wrd_buf);
|
||||
}
|
||||
|
||||
FREE(wrd_buf);
|
||||
|
||||
if (strcasecmp (text, word) <= 0) {
|
||||
initial_offset = get_uint32 (buffer + i + word_len + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
i += word_len + sizeof (unsigned char) + sizeof(uint32_t) +
|
||||
sizeof(uint16_t);
|
||||
}
|
||||
}
|
||||
|
||||
if(initial_offset == test_offset)
|
||||
initial_offset = 0;
|
||||
|
||||
FREE(word);
|
||||
FREE(buffer);
|
||||
|
||||
return initial_offset;
|
||||
}
|
||||
|
||||
static int
|
||||
pychm_process_wlc (struct chmFile *chmfile,
|
||||
uint64_t wlc_count, uint64_t wlc_size,
|
||||
uint32_t wlc_offset, unsigned char ds,
|
||||
unsigned char dr, unsigned char cs,
|
||||
unsigned char cr, unsigned char ls,
|
||||
unsigned char lr, struct chmUnitInfo *uimain,
|
||||
struct chmUnitInfo* uitbl,
|
||||
struct chmUnitInfo *uistrings,
|
||||
struct chmUnitInfo* topics,
|
||||
struct chmUnitInfo *urlstr,
|
||||
PyObject *dict)
|
||||
{
|
||||
uint32_t stroff, urloff;
|
||||
uint64_t i, j, count;
|
||||
size_t length;
|
||||
int wlc_bit = 7;
|
||||
size_t off = 0;
|
||||
uint64_t index = 0;
|
||||
unsigned char entry[TOPICS_ENTRY_LEN];
|
||||
unsigned char combuf[COMMON_BUF_LEN];
|
||||
unsigned char *buffer = malloc (wlc_size);
|
||||
char *url = NULL;
|
||||
char *topic = NULL;
|
||||
|
||||
if (chm_retrieve_object(chmfile, uimain, buffer,
|
||||
wlc_offset, wlc_size) == 0) {
|
||||
FREE(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < wlc_count; ++i) {
|
||||
|
||||
if(wlc_bit != 7) {
|
||||
++off;
|
||||
wlc_bit = 7;
|
||||
}
|
||||
|
||||
index += sr_int(buffer + off, &wlc_bit, ds, dr, &length);
|
||||
off += length;
|
||||
|
||||
if(chm_retrieve_object(chmfile, topics, entry,
|
||||
index * 16, TOPICS_ENTRY_LEN) == 0) {
|
||||
FREE(topic);
|
||||
FREE(url);
|
||||
FREE(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
combuf[COMMON_BUF_LEN - 1] = 0;
|
||||
stroff = get_uint32 (entry + 4);
|
||||
|
||||
FREE (topic);
|
||||
if (chm_retrieve_object (chmfile, uistrings, combuf,
|
||||
stroff, COMMON_BUF_LEN - 1) == 0) {
|
||||
topic = strdup ("Untitled in index");
|
||||
|
||||
} else {
|
||||
combuf[COMMON_BUF_LEN - 1] = 0;
|
||||
|
||||
topic = strdup ((char *)combuf);
|
||||
}
|
||||
|
||||
urloff = get_uint32 (entry + 8);
|
||||
|
||||
if(chm_retrieve_object (chmfile, uitbl, combuf,
|
||||
urloff, 12) == 0) {
|
||||
FREE(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
urloff = get_uint32 (combuf + 8);
|
||||
|
||||
if (chm_retrieve_object (chmfile, urlstr, combuf,
|
||||
urloff + 8, COMMON_BUF_LEN - 1) == 0) {
|
||||
FREE(topic);
|
||||
FREE(url);
|
||||
FREE(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
combuf[COMMON_BUF_LEN - 1] = 0;
|
||||
|
||||
FREE (url);
|
||||
url = strdup ((char *)combuf);
|
||||
|
||||
if (url && topic) {
|
||||
#ifdef __PYTHON__
|
||||
PyDict_SetItem(dict,
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyBytes_FromStringAndSize(topic, strlen(topic)),
|
||||
PyBytes_FromStringAndSize(url, strlen(url))
|
||||
#else
|
||||
PyString_FromString (topic),
|
||||
PyString_FromString (url)
|
||||
#endif
|
||||
);
|
||||
#else
|
||||
printf ("%s ==> %s\n", url, topic);
|
||||
#endif
|
||||
}
|
||||
|
||||
count = sr_int (buffer + off, &wlc_bit, cs, cr, &length);
|
||||
off += length;
|
||||
|
||||
for (j = 0; j < count; ++j) {
|
||||
sr_int (buffer + off, &wlc_bit, ls, lr, &length);
|
||||
off += length;
|
||||
}
|
||||
}
|
||||
|
||||
FREE(topic);
|
||||
FREE(url);
|
||||
FREE(buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
chm_search (struct chmFile *chmfile,
|
||||
const char *text, int whole_words,
|
||||
int titles_only, PyObject *dict)
|
||||
{
|
||||
unsigned char header[FTS_HEADER_LEN];
|
||||
unsigned char doc_index_s;
|
||||
unsigned char doc_index_r;
|
||||
unsigned char code_count_s;
|
||||
unsigned char code_count_r;
|
||||
unsigned char loc_codes_s;
|
||||
unsigned char loc_codes_r;
|
||||
unsigned char word_len, pos;
|
||||
unsigned char *buffer;
|
||||
char *word = NULL;
|
||||
uint32_t node_offset;
|
||||
uint32_t node_len;
|
||||
uint16_t tree_depth;
|
||||
uint32_t i;
|
||||
uint16_t free_space;
|
||||
uint64_t wlc_count, wlc_size;
|
||||
uint32_t wlc_offset;
|
||||
char *wrd_buf;
|
||||
unsigned char title;
|
||||
size_t encsz;
|
||||
struct chmUnitInfo ui, uitopics, uiurltbl, uistrings, uiurlstr;
|
||||
int partial = false;
|
||||
|
||||
if (NULL == text)
|
||||
return -1;
|
||||
|
||||
if (chm_resolve_object (chmfile, "/$FIftiMain", &ui) !=
|
||||
CHM_RESOLVE_SUCCESS ||
|
||||
chm_resolve_object (chmfile, "/#TOPICS", &uitopics) !=
|
||||
CHM_RESOLVE_SUCCESS ||
|
||||
chm_resolve_object (chmfile, "/#STRINGS", &uistrings) !=
|
||||
CHM_RESOLVE_SUCCESS ||
|
||||
chm_resolve_object (chmfile, "/#URLTBL", &uiurltbl) !=
|
||||
CHM_RESOLVE_SUCCESS ||
|
||||
chm_resolve_object (chmfile, "/#URLSTR", &uiurlstr) !=
|
||||
CHM_RESOLVE_SUCCESS)
|
||||
return false;
|
||||
|
||||
if(chm_retrieve_object(chmfile, &ui, header, 0, FTS_HEADER_LEN) == 0)
|
||||
return false;
|
||||
|
||||
doc_index_s = header[0x1E];
|
||||
doc_index_r = header[0x1F];
|
||||
code_count_s = header[0x20];
|
||||
code_count_r = header[0x21];
|
||||
loc_codes_s = header[0x22];
|
||||
loc_codes_r = header[0x23];
|
||||
|
||||
if(doc_index_s != 2 || code_count_s != 2 || loc_codes_s != 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
node_offset = get_uint32 (header + 0x14);
|
||||
node_len = get_uint32 (header + 0x2e);
|
||||
tree_depth = get_uint16 (header + 0x18);
|
||||
|
||||
i = sizeof(uint16_t);
|
||||
|
||||
buffer = malloc (node_len);
|
||||
|
||||
node_offset = get_leaf_node_offset (chmfile, text, node_offset, node_len,
|
||||
tree_depth, &ui);
|
||||
|
||||
if (!node_offset) {
|
||||
FREE(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
|
||||
if (chm_retrieve_object (chmfile, &ui, buffer,
|
||||
node_offset, node_len) == 0) {
|
||||
FREE(word);
|
||||
FREE(buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
free_space = get_uint16 (buffer + 6);
|
||||
|
||||
i = sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t);
|
||||
|
||||
encsz = 0;
|
||||
|
||||
while (i < node_len - free_space) {
|
||||
word_len = *(buffer + i);
|
||||
pos = *(buffer + i + 1);
|
||||
|
||||
wrd_buf = malloc (word_len);
|
||||
memcpy (wrd_buf, buffer + i + 2, word_len - 1);
|
||||
wrd_buf[word_len - 1] = 0;
|
||||
|
||||
if (pos == 0) {
|
||||
FREE(word);
|
||||
word = (char *) strdup (wrd_buf);
|
||||
} else {
|
||||
word = realloc (word, word_len + pos + 1);
|
||||
strcpy (word + pos, wrd_buf);
|
||||
}
|
||||
|
||||
FREE(wrd_buf);
|
||||
|
||||
i += 2 + word_len;
|
||||
title = *(buffer + i - 1);
|
||||
|
||||
wlc_count = be_encint (buffer + i, &encsz);
|
||||
i += encsz;
|
||||
|
||||
wlc_offset = get_uint32 (buffer + i);
|
||||
|
||||
i += sizeof(uint32_t) + sizeof(uint16_t);
|
||||
wlc_size = be_encint (buffer + i, &encsz);
|
||||
i += encsz;
|
||||
|
||||
node_offset = get_uint32 (buffer);
|
||||
|
||||
if (!title && titles_only)
|
||||
continue;
|
||||
|
||||
if (whole_words && !strcasecmp(text, word)) {
|
||||
partial = pychm_process_wlc (chmfile, wlc_count, wlc_size,
|
||||
wlc_offset, doc_index_s,
|
||||
doc_index_r,code_count_s,
|
||||
code_count_r, loc_codes_s,
|
||||
loc_codes_r, &ui, &uiurltbl,
|
||||
&uistrings, &uitopics,
|
||||
&uiurlstr, dict);
|
||||
FREE(word);
|
||||
FREE(buffer);
|
||||
return partial;
|
||||
}
|
||||
|
||||
if (!whole_words) {
|
||||
if (!strncasecmp (word, text, strlen(text))) {
|
||||
partial = true;
|
||||
pychm_process_wlc (chmfile, wlc_count, wlc_size,
|
||||
wlc_offset, doc_index_s,
|
||||
doc_index_r,code_count_s,
|
||||
code_count_r, loc_codes_s,
|
||||
loc_codes_r, &ui, &uiurltbl,
|
||||
&uistrings, &uitopics,
|
||||
&uiurlstr, dict);
|
||||
|
||||
} else if (strncasecmp (text, word, strlen(text)) < -1)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
} while (!whole_words &&
|
||||
!strncmp (word, text, strlen(text)) &&
|
||||
node_offset);
|
||||
|
||||
FREE(word);
|
||||
FREE(buffer);
|
||||
|
||||
return partial;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *file;
|
||||
int offset;
|
||||
} Langrec;
|
||||
|
||||
static Langrec lang_files[] = {
|
||||
{"/$FIftiMain", 0x7E},
|
||||
{"$WWKeywordLinks/BTree", 0x34},
|
||||
{"$WWAssociativeLinks/BTree", 0x34}
|
||||
};
|
||||
|
||||
#define LANG_FILES_SIZE (sizeof(lang_files)/sizeof(Langrec))
|
||||
|
||||
static int
|
||||
chm_get_lcid (struct chmFile *chmfile) {
|
||||
struct chmUnitInfo ui;
|
||||
uint32_t lang;
|
||||
int i;
|
||||
|
||||
for (i=0; i<LANG_FILES_SIZE; i++) {
|
||||
|
||||
if (chm_resolve_object (chmfile, lang_files[i].file, &ui) ==
|
||||
CHM_RESOLVE_SUCCESS) {
|
||||
|
||||
if (chm_retrieve_object (chmfile, &ui, (unsigned char *) &lang,
|
||||
lang_files[i].offset, sizeof(uint32_t)) != 0)
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __PYTHON__
|
||||
|
||||
static PyObject *
|
||||
is_searchable (PyObject *self, PyObject *args) {
|
||||
struct chmFile *file;
|
||||
PyObject *obj0;
|
||||
struct chmUnitInfo ui;
|
||||
|
||||
if (PyArg_ParseTuple (args, "O:is_searchable", &obj0)) {
|
||||
|
||||
file = (struct chmFile *) ((SwigPyObject*)(obj0))->ptr;
|
||||
|
||||
if (chm_resolve_object (file, "/$FIftiMain", &ui) !=
|
||||
CHM_RESOLVE_SUCCESS ||
|
||||
chm_resolve_object (file, "/#TOPICS", &ui) !=
|
||||
CHM_RESOLVE_SUCCESS ||
|
||||
chm_resolve_object (file, "/#STRINGS", &ui) !=
|
||||
CHM_RESOLVE_SUCCESS ||
|
||||
chm_resolve_object (file, "/#URLTBL", &ui) !=
|
||||
CHM_RESOLVE_SUCCESS ||
|
||||
chm_resolve_object (file, "/#URLSTR", &ui) !=
|
||||
CHM_RESOLVE_SUCCESS)
|
||||
return Py_BuildValue ("i", 0);
|
||||
else
|
||||
return Py_BuildValue ("i", 1);
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "Expected chmfile (not CHMFile!)");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
search (PyObject *self, PyObject *args) {
|
||||
char *text;
|
||||
int whole_words = 0;
|
||||
int titles_only = 0;
|
||||
int partial;
|
||||
struct chmFile *file;
|
||||
PyObject *obj0;
|
||||
PyObject *dict;
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject *obj1;
|
||||
if (PyArg_ParseTuple (args, "OSii:search", &obj0, &obj1,
|
||||
#else
|
||||
if (PyArg_ParseTuple (args, "Osii:search", &obj0, &text,
|
||||
#endif
|
||||
&whole_words, &titles_only)) {
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
text = PyBytes_AsString(obj1);
|
||||
#endif
|
||||
dict = PyDict_New();
|
||||
|
||||
if (dict) {
|
||||
file = (struct chmFile *) ((SwigPyObject*)(obj0))->ptr;
|
||||
|
||||
partial = chm_search (file,
|
||||
text, whole_words, titles_only, dict);
|
||||
return Py_BuildValue ("(iO)", partial, dict);
|
||||
|
||||
} else {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Expected chmfile (not CHMFile!), string, int, int");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_lcid (PyObject *self, PyObject *args) {
|
||||
int code;
|
||||
struct chmFile *file;
|
||||
PyObject *obj0;
|
||||
|
||||
if (PyArg_ParseTuple (args, "O:get_lcid", &obj0)) {
|
||||
|
||||
file = (struct chmFile *) ((SwigPyObject*)(obj0))->ptr;
|
||||
|
||||
code = chm_get_lcid (file);
|
||||
|
||||
if (code != -1)
|
||||
return Py_BuildValue ("i", code);
|
||||
else
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError,"Expected a chmfile (not a CHMFile!)");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static PyMethodDef
|
||||
IndexMethods[] = {
|
||||
{"get_lcid", get_lcid, METH_VARARGS,
|
||||
"Returns LCID (Locale ID) for archive."},
|
||||
{"search", search, METH_VARARGS,
|
||||
"Perform Full-Text search."},
|
||||
{"is_searchable", is_searchable, METH_VARARGS,
|
||||
"Return 1 if it is possible to search the archive, 0 otherwise."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"extra",
|
||||
NULL,
|
||||
-1,
|
||||
IndexMethods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define INITERROR return NULL
|
||||
|
||||
#else /* python < 3 */
|
||||
|
||||
#define INITERROR return
|
||||
|
||||
#endif /* python 3/2 */
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyObject* PyInit_extra(void)
|
||||
#else
|
||||
void initextra (void)
|
||||
#endif
|
||||
{
|
||||
PyObject *module;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
module = PyModule_Create(&moduledef);
|
||||
#else
|
||||
module = Py_InitModule ("extra", IndexMethods);
|
||||
#endif
|
||||
if (module == NULL)
|
||||
INITERROR;
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return module;
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
struct chmFile *file;
|
||||
char text[255];
|
||||
int whole_words, titles_only;
|
||||
int partial;
|
||||
|
||||
if (argc == 2) {
|
||||
file = chm_open (argv[1]);
|
||||
|
||||
if (file) {
|
||||
printf ("\nLCID= %d (%08X)\n", chm_get_lcid(file), chm_get_lcid(file));
|
||||
while (1) {
|
||||
printf ("\n<whole_words> <titles_only> <string>\n");
|
||||
printf ("> ");
|
||||
if (scanf ("%d %d %s", &whole_words, &titles_only, text))
|
||||
partial = chm_search (file,
|
||||
text, whole_words, titles_only, NULL);
|
||||
else
|
||||
break;
|
||||
|
||||
printf ("Partial = %d\n", partial);
|
||||
}
|
||||
|
||||
chm_close (file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
} else {
|
||||
printf ("\n%s <filename>\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
4962
src/python/pychm/chm/swig_chm.c
Normal file
4962
src/python/pychm/chm/swig_chm.c
Normal file
File diff suppressed because it is too large
Load Diff
225
src/python/pychm/chm/swig_chm.i
Normal file
225
src/python/pychm/chm/swig_chm.i
Normal file
@ -0,0 +1,225 @@
|
||||
%module chmlib
|
||||
%begin %{
|
||||
#define SWIG_PYTHON_STRICT_BYTE_CHAR
|
||||
%}
|
||||
|
||||
%include "typemaps.i"
|
||||
%include "cstring.i"
|
||||
|
||||
%{
|
||||
/*
|
||||
Copyright (C) 2003 Rubens Ramos <rubensr@users.sourceforge.net>
|
||||
|
||||
Based on code by:
|
||||
Copyright (C) 2003 Razvan Cojocaru <razvanco@gmx.net>
|
||||
|
||||
pychm is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program 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. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public
|
||||
License along with this program; see the file COPYING. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
#include "chm_lib.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static PyObject *my_callback = NULL;
|
||||
|
||||
static PyObject *
|
||||
my_set_callback(PyObject *dummy, PyObject *arg)
|
||||
{
|
||||
PyObject *result = NULL;
|
||||
|
||||
if (!PyCallable_Check(arg)) {
|
||||
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
|
||||
return NULL;
|
||||
}
|
||||
Py_XINCREF(arg); /* Add a reference to new callback */
|
||||
Py_XDECREF(my_callback); /* Dispose of previous callback */
|
||||
my_callback = arg; /* Remember new callback */
|
||||
/* Boilerplate to return "None" */
|
||||
Py_INCREF(Py_None);
|
||||
result = Py_None;
|
||||
return result;
|
||||
}
|
||||
|
||||
int dummy_enumerator (struct chmFile *h,
|
||||
struct chmUnitInfo *ui,
|
||||
void *context) {
|
||||
PyObject *arglist;
|
||||
PyObject *result;
|
||||
PyObject *py_h;
|
||||
PyObject *py_ui;
|
||||
PyObject *py_c;
|
||||
|
||||
py_h = SWIG_NewPointerObj((void *) h, SWIGTYPE_p_chmFile, 0);
|
||||
py_ui = SWIG_NewPointerObj((void *) ui, SWIGTYPE_p_chmUnitInfo, 0);
|
||||
/* The following was: py_c = PyCObject_AsVoidPtr(context); which did
|
||||
not make sense because the function takes a PyObject * and returns a
|
||||
void *, not the reverse. This was probably never used?? In doubt,
|
||||
replace with a call which makes sense and hope for the best... */
|
||||
py_c = PyCapsule_New(context, "context", NULL);
|
||||
|
||||
/* Time to call the callback */
|
||||
arglist = Py_BuildValue("(OOO)", py_h, py_ui, py_c);
|
||||
if (arglist) {
|
||||
result = PyEval_CallObject(my_callback, arglist);
|
||||
Py_DECREF(arglist);
|
||||
Py_DECREF(result);
|
||||
|
||||
Py_DECREF(py_h);
|
||||
Py_DECREF(py_ui);
|
||||
Py_DECREF(py_c);
|
||||
|
||||
if (result == NULL) {
|
||||
return 0; /* Pass error back */
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
%}
|
||||
|
||||
%typemap(in) CHM_ENUMERATOR {
|
||||
if (!my_set_callback(self, $input)) goto fail;
|
||||
$1 = dummy_enumerator;
|
||||
}
|
||||
|
||||
%typemap(in) void *context {
|
||||
if (!($1 = PyCapsule_New($input, "context", NULL))) goto fail;
|
||||
}
|
||||
|
||||
%typemap(in, numinputs=0) struct chmUnitInfo *OutValue (struct chmUnitInfo *temp = (struct chmUnitInfo *) calloc(1, sizeof(struct chmUnitInfo))) {
|
||||
$1 = temp;
|
||||
}
|
||||
|
||||
%typemap(argout) struct chmUnitInfo *OutValue {
|
||||
PyObject *o, *o2, *o3;
|
||||
o = SWIG_NewPointerObj((void *) $1, SWIGTYPE_p_chmUnitInfo, 1);
|
||||
if ((!$result) || ($result == Py_None)) {
|
||||
$result = o;
|
||||
} else {
|
||||
if (!PyTuple_Check($result)) {
|
||||
PyObject *o2 = $result;
|
||||
$result = PyTuple_New(1);
|
||||
PyTuple_SetItem($result,0,o2);
|
||||
}
|
||||
o3 = PyTuple_New(1);
|
||||
PyTuple_SetItem(o3,0,o);
|
||||
o2 = $result;
|
||||
$result = PySequence_Concat(o2,o3);
|
||||
Py_DECREF(o2);
|
||||
Py_DECREF(o3);
|
||||
}
|
||||
}
|
||||
|
||||
%typemap(check) unsigned char *OUTPUT {
|
||||
/* nasty hack */
|
||||
#ifdef __cplusplus
|
||||
$1 = ($1_ltype) new char[arg5];
|
||||
#else
|
||||
$1 = ($1_ltype) malloc(arg5);
|
||||
#endif
|
||||
if ($1 == NULL) SWIG_fail;
|
||||
}
|
||||
|
||||
%typemap(argout,fragment="t_output_helper") unsigned char *OUTPUT {
|
||||
PyObject *o;
|
||||
o = SWIG_FromCharPtrAndSize((const char*)$1, arg5);
|
||||
/* o = PyString_FromStringAndSize($1, arg5);*/
|
||||
$result = t_output_helper($result,o);
|
||||
#ifdef __cplusplus
|
||||
delete [] $1;
|
||||
#else
|
||||
free($1);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
typedef unsigned __int64 LONGUINT64;
|
||||
typedef __int64 LONGINT64;
|
||||
#else
|
||||
typedef unsigned long long LONGUINT64;
|
||||
typedef long long LONGINT64;
|
||||
#endif
|
||||
|
||||
/* the two available spaces in a CHM file */
|
||||
/* N.B.: The format supports arbitrarily many spaces, but only */
|
||||
/* two appear to be used at present. */
|
||||
#define CHM_UNCOMPRESSED (0)
|
||||
#define CHM_COMPRESSED (1)
|
||||
|
||||
/* structure representing an ITS (CHM) file stream */
|
||||
struct chmFile;
|
||||
|
||||
/* structure representing an element from an ITS file stream */
|
||||
#define CHM_MAX_PATHLEN 256
|
||||
struct chmUnitInfo
|
||||
{
|
||||
LONGUINT64 start;
|
||||
LONGUINT64 length;
|
||||
int space;
|
||||
char path[CHM_MAX_PATHLEN+1];
|
||||
};
|
||||
|
||||
/* open an ITS archive */
|
||||
struct chmFile* chm_open(const char *filename);
|
||||
|
||||
/* close an ITS archive */
|
||||
void chm_close(struct chmFile *h);
|
||||
|
||||
/* methods for ssetting tuning parameters for particular file */
|
||||
#define CHM_PARAM_MAX_BLOCKS_CACHED 0
|
||||
void chm_set_param(struct chmFile *h,
|
||||
int paramType,
|
||||
int paramVal);
|
||||
|
||||
/* resolve a particular object from the archive */
|
||||
#define CHM_RESOLVE_SUCCESS (0)
|
||||
#define CHM_RESOLVE_FAILURE (1)
|
||||
int chm_resolve_object(struct chmFile *h,
|
||||
const char *objPath,
|
||||
struct chmUnitInfo *OutValue);
|
||||
|
||||
/* retrieve part of an object from the archive */
|
||||
LONGINT64 chm_retrieve_object(struct chmFile *h,
|
||||
struct chmUnitInfo *ui,
|
||||
unsigned char *OUTPUT,
|
||||
LONGUINT64 addr,
|
||||
LONGINT64 len);
|
||||
|
||||
/* enumerate the objects in the .chm archive */
|
||||
typedef int (*CHM_ENUMERATOR)(struct chmFile *h,
|
||||
struct chmUnitInfo *ui,
|
||||
void *context);
|
||||
#define CHM_ENUMERATE_NORMAL (1)
|
||||
#define CHM_ENUMERATE_META (2)
|
||||
#define CHM_ENUMERATE_SPECIAL (4)
|
||||
#define CHM_ENUMERATE_FILES (8)
|
||||
#define CHM_ENUMERATE_DIRS (16)
|
||||
#define CHM_ENUMERATE_ALL (31)
|
||||
#define CHM_ENUMERATOR_FAILURE (0)
|
||||
#define CHM_ENUMERATOR_CONTINUE (1)
|
||||
#define CHM_ENUMERATOR_SUCCESS (2)
|
||||
int chm_enumerate(struct chmFile *h,
|
||||
int what,
|
||||
CHM_ENUMERATOR e,
|
||||
void *context);
|
||||
|
||||
int chm_enumerate_dir(struct chmFile *h,
|
||||
const char *prefix,
|
||||
int what,
|
||||
CHM_ENUMERATOR e,
|
||||
void *context);
|
||||
15
src/python/pychm/pychm.egg-info/PKG-INFO
Normal file
15
src/python/pychm/pychm.egg-info/PKG-INFO
Normal file
@ -0,0 +1,15 @@
|
||||
Metadata-Version: 1.0
|
||||
Name: pychm
|
||||
Version: 0.8.4.1+git
|
||||
Summary: Python package to handle CHM files
|
||||
Home-page: https://github.com/dottedmag/pychm
|
||||
Author: Mikhail Gusarov
|
||||
Author-email: dottedmag@dottedmag.net
|
||||
License: GPL
|
||||
Description:
|
||||
The chm package provides three modules, chm, chmlib and extra, which provide
|
||||
access to the API implemented by the C library chmlib and some additional
|
||||
classes and functions. They are used to access MS-ITSS encoded files -
|
||||
Compressed Html Help files (.chm).
|
||||
|
||||
Platform: UNKNOWN
|
||||
11
src/python/pychm/pychm.egg-info/SOURCES.txt
Normal file
11
src/python/pychm/pychm.egg-info/SOURCES.txt
Normal file
@ -0,0 +1,11 @@
|
||||
setup.py
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/../../python/pychm/chm/__init__.py
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/../../python/pychm/chm/chm.py
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/../../python/pychm/chm/chmlib.py
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/../../python/pychm/pychm.egg-info/PKG-INFO
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/../../python/pychm/pychm.egg-info/SOURCES.txt
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/../../python/pychm/pychm.egg-info/SOURCES.txt~
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/../../python/pychm/pychm.egg-info/dependency_links.txt
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/../../python/pychm/pychm.egg-info/top_level.txt
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/chm/extra.c
|
||||
/home/dockes/projets/fulltext/recoll/src/python/pychm/chm/swig_chm.c
|
||||
1
src/python/pychm/pychm.egg-info/dependency_links.txt
Normal file
1
src/python/pychm/pychm.egg-info/dependency_links.txt
Normal file
@ -0,0 +1 @@
|
||||
|
||||
1
src/python/pychm/pychm.egg-info/top_level.txt
Normal file
1
src/python/pychm/pychm.egg-info/top_level.txt
Normal file
@ -0,0 +1 @@
|
||||
chm
|
||||
35
src/python/pychm/setup.py.in
Normal file
35
src/python/pychm/setup.py.in
Normal file
@ -0,0 +1,35 @@
|
||||
from setuptools import setup, Extension
|
||||
|
||||
long_description = '''
|
||||
The chm package provides three modules, chm, chmlib and extra, which provide
|
||||
access to the API implemented by the C library chmlib and some additional
|
||||
classes and functions. They are used to access MS-ITSS encoded files -
|
||||
Compressed Html Help files (.chm).
|
||||
'''
|
||||
|
||||
# For shadow builds: references to the source tree
|
||||
import os
|
||||
top = os.path.join('@srcdir@', '..', '..')
|
||||
pytop = '@srcdir@'
|
||||
|
||||
setup(name="pychm",
|
||||
version="0.8.4.1+git",
|
||||
description="Python package to handle CHM files",
|
||||
author="Rubens Ramos",
|
||||
author_email="rubensr@users.sourceforge.net",
|
||||
maintainer="Mikhail Gusarov",
|
||||
maintainer_email="dottedmag@dottedmag.net",
|
||||
url="https://github.com/dottedmag/pychm",
|
||||
license="GPL",
|
||||
long_description=long_description,
|
||||
package_dir = {'' : os.path.join(top, 'python', 'pychm')},
|
||||
py_modules=["chm.chm", "chm.chmlib"],
|
||||
ext_modules=[Extension("chm._chmlib",
|
||||
[os.path.join(pytop, "chm/swig_chm.c")],
|
||||
libraries=["chm"],
|
||||
extra_compile_args=["-DSWIG_COBJECT_TYPES"]),
|
||||
Extension("chm.extra",
|
||||
[os.path.join(pytop, "chm/extra.c")],
|
||||
extra_compile_args=["-D__PYTHON__"],
|
||||
libraries=["chm"])]
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user