Browse Source

--- Merging r15548 into '.':
U packages/chm/fpmake.pp
U packages/chm/Makefile.fpc
A packages/chm/src/itsftransform.pas
A packages/chm/src/itolitlsreader.pas
A packages/chm/src/itolitlstypes.pas
C packages/chm/Makefile
--- Merging r15549 into '.':
U packages/chm/src/itsftransform.pas
U packages/chm/src/itolitlsreader.pas
U packages/chm/src/itolitlstypes.pas
--- Merging r15554 into '.':
U packages/chm/src/chmwriter.pas
--- Merging r15573 into '.':
U packages/chm/src/chmfiftimain.pas
G packages/chm/src/chmwriter.pas
--- Merging r15579 into '.':
U packages/chm/src/chmfilewriter.pas
--- Merging r15584 into '.':
G packages/chm/src/chmfiftimain.pas
--- Merging r15590 into '.':
U packages/fcl-passrc/src/pastree.pp
U packages/fcl-passrc/src/pscanner.pp
U packages/fcl-passrc/src/pparser.pp
--- Merging r15591 into '.':
U packages/chm/src/chmls.lpr
--- Merging r15592 into '.':
U packages/chm/src/chmreader.pas
--- Merging r15593 into '.':
G packages/chm/Makefile.fpc
G packages/chm/src/chmls.lpr
D packages/chm/src/unblockchm.pp
C packages/chm/Makefile
Summary of conflicts:
Text conflicts: 2

# revisions: 15182,15444,15547,15548,15549,15550,15554,15558,15559,15563,15573,15578,15579,15584,15590,15591,15592,15593
------------------------------------------------------------------------
r15182 | marco | 2010-04-26 15:17:26 +0200 (Mon, 26 Apr 2010) | 2 lines
Changed paths:
A /trunk/packages/fcl-passrc/examples
A /trunk/packages/fcl-passrc/examples/test_parser.pp
M /trunk/packages/fcl-passrc/src/pscanner.pp

* fix for mantis 16344 (quoted filename in $include ) + testparser example from that series of bugreports.

------------------------------------------------------------------------
------------------------------------------------------------------------
r15444 | marco | 2010-06-17 11:04:25 +0200 (Thu, 17 Jun 2010) | 7 lines
Changed paths:
M /trunk/packages/chm/src/chmfilewriter.pas
M /trunk/packages/chm/src/chmtypes.pas

* initial hhp loading in chmproject.
* chmproject now supports #Windows (the CHM feature, not the OS), but doesn't pass it to writer yet.
* Some keys in chmproject moved from files/ to settings/ were they belong.
hopefully with backwards compat loading capability.

Low errorchecking etc, and only initially tested. Not for 2.4.2

------------------------------------------------------------------------
------------------------------------------------------------------------
r15547 | andrew | 2010-07-11 14:13:36 +0200 (Sun, 11 Jul 2010) | 4 lines
Changed paths:
M /trunk/packages/chm/src/chmbase.pas
M /trunk/packages/chm/src/chmreader.pas
M /trunk/packages/chm/src/chmwriter.pas
M /trunk/packages/chm/src/lzxcompressthread.pas
M /trunk/packages/chm/src/paslzxcomp.pas

* Fixed a potential bug where a value would not change if a contition wasn't met
* Made TITSFReader friendlier for inherited classes
* Small fix for threaded lzx compressor

------------------------------------------------------------------------
------------------------------------------------------------------------
r15548 | andrew | 2010-07-11 14:43:38 +0200 (Sun, 11 Jul 2010) | 2 lines
Changed paths:
M /trunk/packages/chm/Makefile
M /trunk/packages/chm/Makefile.fpc
M /trunk/packages/chm/fpmake.pp
A /trunk/packages/chm/src/itolitlsreader.pas
A /trunk/packages/chm/src/itolitlstypes.pas
A /trunk/packages/chm/src/itsftransform.pas

* added basic reading for ms help 2 the successor to chm

------------------------------------------------------------------------
------------------------------------------------------------------------
r15549 | andrew | 2010-07-11 14:46:36 +0200 (Sun, 11 Jul 2010) | 2 lines
Changed paths:
M /trunk/packages/chm/src/itolitlsreader.pas
M /trunk/packages/chm/src/itolitlstypes.pas
M /trunk/packages/chm/src/itsftransform.pas

* updated copyrights

------------------------------------------------------------------------
------------------------------------------------------------------------
r15550 | marco | 2010-07-11 14:55:56 +0200 (Sun, 11 Jul 2010) | 4 lines
Changed paths:
M /trunk/packages/chm/src/chmcmd.lpr
M /trunk/packages/chm/src/chmfilewriter.pas
M /trunk/packages/chm/src/chmreader.pas
M /trunk/packages/chm/src/chmtypes.pas
M /trunk/packages/chm/src/chmwriter.pas

* initial #windows, defaultwindow support
* initially working .hhp support in chmcmd
* index and toc are not always named default.hh[k/c] anymore, but use the names in the project xml if specified.
* callback to allow basic output for filewriter/chmcmd
------------------------------------------------------------------------
------------------------------------------------------------------------
r15554 | andrew | 2010-07-11 20:52:35 +0200 (Sun, 11 Jul 2010) | 2 lines
Changed paths:
M /trunk/packages/chm/src/chmwriter.pas

* fixed a bug where the header size was incorrectly reported causing useless chm files

------------------------------------------------------------------------
------------------------------------------------------------------------
r15558 | marco | 2010-07-12 22:10:21 +0200 (Mon, 12 Jul 2010) | 1 line
Changed paths:
M /trunk/packages/chm/src/chmcmd.lpr
M /trunk/packages/chm/src/chmfilewriter.pas

* Improved link scanning, and chmcmd commandline handling
------------------------------------------------------------------------
------------------------------------------------------------------------
r15559 | michael | 2010-07-12 22:56:43 +0200 (Mon, 12 Jul 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp
M /trunk/packages/fcl-passrc/src/pparser.pp

* Patch from Dmitry Boyarintsev to implement expression parsing. Improved to have operator as enumerated
------------------------------------------------------------------------
------------------------------------------------------------------------
r15563 | marco | 2010-07-13 19:57:49 +0200 (Tue, 13 Jul 2010) | 3 lines
Changed paths:
M /trunk/packages/chm/src/chmcmd.lpr
M /trunk/packages/chm/src/chmls.lpr
M /trunk/packages/chm/src/chmreader.pas

* fixed a problem in chmreader wrt moment of fwindows creation
* removed a redundant line from chmcmd (leftover from the getopts example)
* reworking chmls on a getopts basis, like chmcmd, and make it support extracting files. (no wildcards (yet))
------------------------------------------------------------------------
------------------------------------------------------------------------
r15573 | andrew | 2010-07-15 05:28:43 +0200 (Thu, 15 Jul 2010) | 2 lines
Changed paths:
M /trunk/packages/chm/src/chmfiftimain.pas
M /trunk/packages/chm/src/chmwriter.pas

* fixed a possible chm compiler crash when a chm without .ht* files is created but full search is enabled.

------------------------------------------------------------------------
------------------------------------------------------------------------
r15578 | marco | 2010-07-15 10:58:54 +0200 (Thu, 15 Jul 2010) | 2 lines
Changed paths:
M /trunk/packages/chm/src/chmcmd.lpr
M /trunk/packages/chm/src/chmfilewriter.pas
M /trunk/packages/chm/src/chmls.lpr

* more little fixes from initial testing. Mostly errormessages and .hhp defaults.
chmls -n switch
------------------------------------------------------------------------
------------------------------------------------------------------------
r15579 | marco | 2010-07-15 11:45:41 +0200 (Thu, 15 Jul 2010) | 1 line
Changed paths:
M /trunk/packages/chm/src/chmfilewriter.pas

* two more changed defaults and default parsing errors.
------------------------------------------------------------------------
------------------------------------------------------------------------
r15584 | andrew | 2010-07-15 23:42:02 +0200 (Thu, 15 Jul 2010) | 2 lines
Changed paths:
M /trunk/packages/chm/src/chmfiftimain.pas

* Fixed chm bug that stopped the search db fr ever being written to a file

------------------------------------------------------------------------
------------------------------------------------------------------------
r15590 | michael | 2010-07-16 21:03:47 +0200 (Fri, 16 Jul 2010) | 1 line
Changed paths:
M /trunk/packages/fcl-passrc/src/pastree.pp
M /trunk/packages/fcl-passrc/src/pparser.pp
M /trunk/packages/fcl-passrc/src/pscanner.pp

* Patch from Dmitry Boyarintsev to improve expression parsing (16931).
------------------------------------------------------------------------
------------------------------------------------------------------------
r15591 | marco | 2010-07-16 23:05:32 +0200 (Fri, 16 Jul 2010) | 1 line
Changed paths:
M /trunk/packages/chm/src/chmls.lpr

* added extractall command to extract all files in a chm.
------------------------------------------------------------------------
------------------------------------------------------------------------
r15592 | andrew | 2010-07-17 05:33:28 +0200 (Sat, 17 Jul 2010) | 2 lines
Changed paths:
M /trunk/packages/chm/src/chmreader.pas

* fixed bug #15838 where chm urls might have a backslash in the url

------------------------------------------------------------------------
------------------------------------------------------------------------
r15593 | marco | 2010-07-17 13:52:58 +0200 (Sat, 17 Jul 2010) | 1 line
Changed paths:
M /trunk/packages/chm/Makefile
M /trunk/packages/chm/Makefile.fpc
M /trunk/packages/chm/src/chmls.lpr
D /trunk/packages/chm/src/unblockchm.pp

* unblock folded into chmls and deleted.
------------------------------------------------------------------------

git-svn-id: branches/fixes_2_4@16363 -

marco 14 years ago
parent
commit
5916e458db

+ 3 - 1
.gitattributes

@@ -975,11 +975,13 @@ packages/chm/src/chmwriter.pas svneol=native#text/plain
 packages/chm/src/fasthtmlparser.pas svneol=native#text/plain
 packages/chm/src/fasthtmlparser.pas svneol=native#text/plain
 packages/chm/src/htmlindexer.pas svneol=native#text/plain
 packages/chm/src/htmlindexer.pas svneol=native#text/plain
 packages/chm/src/htmlutil.pas svneol=native#text/plain
 packages/chm/src/htmlutil.pas svneol=native#text/plain
+packages/chm/src/itolitlsreader.pas svneol=native#text/plain
+packages/chm/src/itolitlstypes.pas svneol=native#text/plain
+packages/chm/src/itsftransform.pas svneol=native#text/plain
 packages/chm/src/lzxcompressthread.pas svneol=native#text/plain
 packages/chm/src/lzxcompressthread.pas svneol=native#text/plain
 packages/chm/src/paslznonslide.pas svneol=native#text/plain
 packages/chm/src/paslznonslide.pas svneol=native#text/plain
 packages/chm/src/paslzx.pas svneol=native#text/plain
 packages/chm/src/paslzx.pas svneol=native#text/plain
 packages/chm/src/paslzxcomp.pas svneol=native#text/plain
 packages/chm/src/paslzxcomp.pas svneol=native#text/plain
-packages/chm/src/unblockchm.pp -text svneol=native#test/plain
 packages/dbus/Makefile svneol=native#text/plain
 packages/dbus/Makefile svneol=native#text/plain
 packages/dbus/Makefile.fpc svneol=native#text/plain
 packages/dbus/Makefile.fpc svneol=native#text/plain
 packages/dbus/examples/Makefile svneol=native#text/plain
 packages/dbus/examples/Makefile svneol=native#text/plain

+ 65 - 63
packages/chm/Makefile

@@ -273,7 +273,7 @@ ifeq ($(FULL_TARGET),i386-go32v2)
 override TARGET_PROGRAMS+=chmcmd chmls
 override TARGET_PROGRAMS+=chmcmd chmls
 endif
 endif
 ifeq ($(FULL_TARGET),i386-win32)
 ifeq ($(FULL_TARGET),i386-win32)
-override TARGET_PROGRAMS+=chmcmd chmls  unblockchm
+override TARGET_PROGRAMS+=chmcmd chmls
 endif
 endif
 ifeq ($(FULL_TARGET),i386-os2)
 ifeq ($(FULL_TARGET),i386-os2)
 override TARGET_PROGRAMS+=chmcmd chmls
 override TARGET_PROGRAMS+=chmcmd chmls
@@ -396,7 +396,7 @@ ifeq ($(FULL_TARGET),x86_64-darwin)
 override TARGET_PROGRAMS+=chmcmd chmls
 override TARGET_PROGRAMS+=chmcmd chmls
 endif
 endif
 ifeq ($(FULL_TARGET),x86_64-win64)
 ifeq ($(FULL_TARGET),x86_64-win64)
-override TARGET_PROGRAMS+=chmcmd chmls  unblockchm
+override TARGET_PROGRAMS+=chmcmd chmls
 endif
 endif
 ifeq ($(FULL_TARGET),x86_64-embedded)
 ifeq ($(FULL_TARGET),x86_64-embedded)
 override TARGET_PROGRAMS+=chmcmd chmls
 override TARGET_PROGRAMS+=chmcmd chmls
@@ -447,184 +447,187 @@ ifeq ($(FULL_TARGET),mipsel-linux)
 override TARGET_PROGRAMS+=chmcmd chmls
 override TARGET_PROGRAMS+=chmcmd chmls
 endif
 endif
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-go32v2)
 ifeq ($(FULL_TARGET),i386-go32v2)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-win32)
 ifeq ($(FULL_TARGET),i386-win32)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-os2)
 ifeq ($(FULL_TARGET),i386-os2)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-freebsd)
 ifeq ($(FULL_TARGET),i386-freebsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-beos)
 ifeq ($(FULL_TARGET),i386-beos)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-haiku)
 ifeq ($(FULL_TARGET),i386-haiku)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-netbsd)
 ifeq ($(FULL_TARGET),i386-netbsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-solaris)
 ifeq ($(FULL_TARGET),i386-solaris)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-qnx)
 ifeq ($(FULL_TARGET),i386-qnx)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-netware)
 ifeq ($(FULL_TARGET),i386-netware)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-openbsd)
 ifeq ($(FULL_TARGET),i386-openbsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-wdosx)
 ifeq ($(FULL_TARGET),i386-wdosx)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-darwin)
 ifeq ($(FULL_TARGET),i386-darwin)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-emx)
 ifeq ($(FULL_TARGET),i386-emx)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-watcom)
 ifeq ($(FULL_TARGET),i386-watcom)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-netwlibc)
 ifeq ($(FULL_TARGET),i386-netwlibc)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-wince)
 ifeq ($(FULL_TARGET),i386-wince)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-embedded)
 ifeq ($(FULL_TARGET),i386-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),i386-symbian)
 ifeq ($(FULL_TARGET),i386-symbian)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
+endif
+ifeq ($(FULL_TARGET),i386-nativent)
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),m68k-linux)
 ifeq ($(FULL_TARGET),m68k-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),m68k-freebsd)
 ifeq ($(FULL_TARGET),m68k-freebsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),m68k-netbsd)
 ifeq ($(FULL_TARGET),m68k-netbsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),m68k-amiga)
 ifeq ($(FULL_TARGET),m68k-amiga)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),m68k-atari)
 ifeq ($(FULL_TARGET),m68k-atari)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),m68k-openbsd)
 ifeq ($(FULL_TARGET),m68k-openbsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),m68k-palmos)
 ifeq ($(FULL_TARGET),m68k-palmos)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),m68k-embedded)
 ifeq ($(FULL_TARGET),m68k-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc-linux)
 ifeq ($(FULL_TARGET),powerpc-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc-netbsd)
 ifeq ($(FULL_TARGET),powerpc-netbsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc-amiga)
 ifeq ($(FULL_TARGET),powerpc-amiga)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc-macos)
 ifeq ($(FULL_TARGET),powerpc-macos)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc-darwin)
 ifeq ($(FULL_TARGET),powerpc-darwin)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc-morphos)
 ifeq ($(FULL_TARGET),powerpc-morphos)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc-embedded)
 ifeq ($(FULL_TARGET),powerpc-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),sparc-linux)
 ifeq ($(FULL_TARGET),sparc-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),sparc-netbsd)
 ifeq ($(FULL_TARGET),sparc-netbsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),sparc-solaris)
 ifeq ($(FULL_TARGET),sparc-solaris)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),sparc-embedded)
 ifeq ($(FULL_TARGET),sparc-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),x86_64-linux)
 ifeq ($(FULL_TARGET),x86_64-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),x86_64-freebsd)
 ifeq ($(FULL_TARGET),x86_64-freebsd)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),x86_64-solaris)
 ifeq ($(FULL_TARGET),x86_64-solaris)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),x86_64-darwin)
 ifeq ($(FULL_TARGET),x86_64-darwin)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),x86_64-win64)
 ifeq ($(FULL_TARGET),x86_64-win64)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),x86_64-embedded)
 ifeq ($(FULL_TARGET),x86_64-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),arm-linux)
 ifeq ($(FULL_TARGET),arm-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),arm-palmos)
 ifeq ($(FULL_TARGET),arm-palmos)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),arm-darwin)
 ifeq ($(FULL_TARGET),arm-darwin)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),arm-wince)
 ifeq ($(FULL_TARGET),arm-wince)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),arm-gba)
 ifeq ($(FULL_TARGET),arm-gba)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),arm-nds)
 ifeq ($(FULL_TARGET),arm-nds)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),arm-embedded)
 ifeq ($(FULL_TARGET),arm-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),arm-symbian)
 ifeq ($(FULL_TARGET),arm-symbian)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc64-linux)
 ifeq ($(FULL_TARGET),powerpc64-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc64-darwin)
 ifeq ($(FULL_TARGET),powerpc64-darwin)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),powerpc64-embedded)
 ifeq ($(FULL_TARGET),powerpc64-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),avr-embedded)
 ifeq ($(FULL_TARGET),avr-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),armeb-linux)
 ifeq ($(FULL_TARGET),armeb-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),armeb-embedded)
 ifeq ($(FULL_TARGET),armeb-embedded)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 ifeq ($(FULL_TARGET),mipsel-linux)
 ifeq ($(FULL_TARGET),mipsel-linux)
-override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread
+override TARGET_UNITS+=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 endif
 endif
 override INSTALL_FPCPACKAGE=y
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
 ifeq ($(FULL_TARGET),i386-linux)
@@ -2864,4 +2867,3 @@ endif
 .NOTPARALLEL:
 .NOTPARALLEL:
 cdmcmd$(EXEEXT): chmcmd.lpr
 cdmcmd$(EXEEXT): chmcmd.lpr
 chmls$(EXEEXT): chmls.lpr
 chmls$(EXEEXT): chmls.lpr
-unblockchm$(EXEEXT): unblockchm.pp

+ 2 - 4
packages/chm/Makefile.fpc

@@ -9,10 +9,8 @@ version=2.4.3
 [target]
 [target]
 units=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes \
 units=fasthtmlparser htmlutil paslzx paslzxcomp paslznonslide chmbase chmtypes \
       chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer \
       chmspecialfiles chmsitemap chmwriter chmfilewriter chmreader htmlindexer \
-      chmfiftimain lzxcompressthread
+      chmfiftimain lzxcompressthread itolitlstypes itsftransform itolitlsreader
 programs=chmcmd chmls
 programs=chmcmd chmls
-programs_win32=unblockchm
-programs_win64=unblockchm
 examples=
 examples=
 
 
 [require]
 [require]
@@ -35,4 +33,4 @@ cdmcmd$(EXEEXT): chmcmd.lpr
 
 
 chmls$(EXEEXT): chmls.lpr
 chmls$(EXEEXT): chmls.lpr
 
 
-unblockchm$(EXEEXT): unblockchm.pp
+

+ 16 - 0
packages/chm/fpmake.pp

@@ -93,6 +93,22 @@ begin
         begin
         begin
           AddUnit('htmlindexer');
           AddUnit('htmlindexer');
         end;
         end;
+   T:=P.Targets.AddUnit('itolitlstypes.pas');
+   T:=P.Targets.AddUnit('itsftransform.pas');
+      with T.Dependencies do
+        begin
+          AddUnit('itolitlstypes');
+          AddUnit('paslzx');
+        end;
+   T:=P.Targets.AddUnit('itolitlsreader.pas');
+      with T.Dependencies do
+        begin  //chmreader, itolitlstypes, Sysutils, chmbase, itsftransform; 
+          AddUnit('chmbase');
+          AddUnit('chmreader');
+          AddUnit('itolitlstypes');
+          AddUnit('itsftransform');
+
+        end;
 
 
 //    P.ProgramPath.Add('src');
 //    P.ProgramPath.Add('src');
     T:=P.Targets.AddProgram('chmls.lpr');
     T:=P.Targets.AddProgram('chmls.lpr');

+ 7 - 0
packages/chm/src/chmfiftimain.pas

@@ -86,11 +86,13 @@ type
     FStream: TStream;
     FStream: TStream;
     FWordList: TIndexedWordList;
     FWordList: TIndexedWordList;
     FActiveLeafNode: TFIftiNode;
     FActiveLeafNode: TFIftiNode;
+    function GetHasData: Boolean;
     procedure ProcessWords;
     procedure ProcessWords;
     procedure WriteHeader(IsPlaceHolder: Boolean);
     procedure WriteHeader(IsPlaceHolder: Boolean);
     procedure WriteAWord(AWord: TIndexedWord);
     procedure WriteAWord(AWord: TIndexedWord);
   public
   public
     procedure WriteToStream;
     procedure WriteToStream;
+    property  HasData: Boolean read GetHasData;
     constructor Create(AStream: TStream; AWordList: TIndexedWordList);
     constructor Create(AStream: TStream; AWordList: TIndexedWordList);
     destructor Destroy; override;
     destructor Destroy; override;
   end;
   end;
@@ -261,6 +263,11 @@ begin
     FActiveLeafNode.Flush(False); // causes the unwritten parts of the tree to be written
     FActiveLeafNode.Flush(False); // causes the unwritten parts of the tree to be written
 end;
 end;
 
 
+function TChmSearchWriter.GetHasData: Boolean;
+begin
+  Result := FWordList.IndexedFileCount > 0;
+end;
+
 
 
 procedure TChmSearchWriter.WriteHeader ( IsPlaceHolder: Boolean ) ;
 procedure TChmSearchWriter.WriteHeader ( IsPlaceHolder: Boolean ) ;
 var
 var

+ 4 - 1
packages/chm/src/chmfilewriter.pas

@@ -218,7 +218,7 @@ Const
        'COMPRESS','COPYRIGHT','COMPATIBILITY','COMPILED FILE','CONTENTS FILE',
        'COMPRESS','COPYRIGHT','COMPATIBILITY','COMPILED FILE','CONTENTS FILE',
        'CREATE CHI FILE','DBCS','DEFAULT FONT','DEFAULT WINDOW','DEFAULT TOPIC',
        'CREATE CHI FILE','DBCS','DEFAULT FONT','DEFAULT WINDOW','DEFAULT TOPIC',
        'DISPLAY COMPILE NOTES','DISPLAY COMPILE PROGRESS','ENHANCED DECOMPILATION','ERROR LOG FILE','FLAT',
        'DISPLAY COMPILE NOTES','DISPLAY COMPILE PROGRESS','ENHANCED DECOMPILATION','ERROR LOG FILE','FLAT',
-       'FULL-TEXT SEARCH STOP LIST','FULL TEXT SEARCH','IGNORE','INDEX FILE','LANGUAGE','PREFIX',
+       'FULL-TEXT SEARCH STOP LIST','FULL-TEXT SEARCH','IGNORE','INDEX FILE','LANGUAGE','PREFIX',
        'SAMPLE STAGING PATH','SAMPLE LIST FILE','TMPDIR','TITLE','CUSTOM TAB','UNKNOWN');
        'SAMPLE STAGING PATH','SAMPLE LIST FILE','TMPDIR','TITLE','CUSTOM TAB','UNKNOWN');
 
 
 
 
@@ -524,6 +524,9 @@ var
   nd        : TChmContextNode;
   nd        : TChmContextNode;
 
 
 begin
 begin
+ { Defaults other than global }
+   MakeBinaryIndex:=True;
+
   Fini:=TMeminiFile.Create(AFileName);
   Fini:=TMeminiFile.Create(AFileName);
   secs := TStringList.create;
   secs := TStringList.create;
   strs := TStringList.create;
   strs := TStringList.create;

+ 212 - 20
packages/chm/src/chmls.lpr

@@ -32,19 +32,27 @@ uses
 
 
 type
 type
 
 
-  { TJunkObject }
+  { TListObject }
 
 
-  TJunkObject = class
+  TListObject = class
     Section  : Integer;
     Section  : Integer;
     count    : integer;
     count    : integer;
     donotpage: boolean;
     donotpage: boolean;
     procedure OnFileEntry(Name: String; Offset, UncompressedSize, ASection: Integer);
     procedure OnFileEntry(Name: String; Offset, UncompressedSize, ASection: Integer);
   end;
   end;
 
 
-  TCmdEnum = (cmdList,cmdExtract,cmdNone);        // One dummy element at the end avoids rangecheck errors.
+   TExtractAllObject = class
+    basedir : string;
+    r       : TChmReader;
+    lastone_was_point : boolean;
+    procedure OnFileEntry(Name: String; Offset, UncompressedSize, ASection: Integer);
+  end;
+
+
+  TCmdEnum = (cmdList,cmdExtract,cmdExtractall,cmdUnblock,cmdNone);        // One dummy element at the end avoids rangecheck errors.
 
 
 Const
 Const
-  CmdNames : array [TCmdEnum] of String = ('LIST','EXTRACT','');
+  CmdNames : array [TCmdEnum] of String = ('LIST','EXTRACT','EXTRACTALL','UNBLOCK','');
 
 
 var
 var
   theopts : array[1..2] of TOption;
   theopts : array[1..2] of TOption;
@@ -60,14 +68,28 @@ begin
   writeln(stderr,' -n          : do not page list output');
   writeln(stderr,' -n          : do not page list output');
   writeln(stderr);
   writeln(stderr);
   writeln(stderr,'Where command is one of the following or if omitted, equal to LIST.');
   writeln(stderr,'Where command is one of the following or if omitted, equal to LIST.');
-  writeln(stderr,' list     <filename> [section number] ');
+  writeln(stderr,' list       <filename> [section number] ');
   writeln(stderr,'            Shows contents of the archive''s directory');
   writeln(stderr,'            Shows contents of the archive''s directory');
-  writeln(stderr,' extract  <chm filename> <filename to extract> [saveasname]');
+  writeln(stderr,' extract    <chm filename> <filename to extract> [saveasname]');
   writeln(stderr,'            Extracts file "filename to get" from archive "filename",');
   writeln(stderr,'            Extracts file "filename to get" from archive "filename",');
   writeln(stderr,'            and, if specified, saves it to [saveasname]');
   writeln(stderr,'            and, if specified, saves it to [saveasname]');
+  writeln(stderr,' extractall <chm filename> [directory]');
+  writeln(stderr,'            Extracts all files from archive "filename" to directory ');
+  writeln(stderr,'            "directory"');
+  writeln(stderr,' unblockchm <filespec1> [filespec2] ..' );
+  writeln(stderr,'            Mass unblocks (XPsp2+) the relevant CHMs. Multiple files');
+  writeln(stderr,'            and wildcards allowed');
   Halt(1);
   Halt(1);
 end;
 end;
 
 
+procedure WrongNrParam(cmd:string;number:integer);
+
+begin
+  writeln(stderr,' Wrong number of parameters for ',cmd,' ',number);
+  usage;
+  halt(1);
+end;
+
 procedure InitOptions;
 procedure InitOptions;
 begin
 begin
   with theopts[1] do
   with theopts[1] do
@@ -98,9 +120,34 @@ procedure WriteStrAdj(Str: String; CharWidth: Integer);
     Write(OutString + Str); // to stdout
     Write(OutString + Str); // to stdout
   end;
   end;
 
 
-{ TJunkObject }
+function craftpath(pth:string;filename:String):string;
+
+var lenpth,lenfn:integer;
+    pthends,filenameends : Boolean;
+begin
+  lenpth:=length(pth); lenfn :=length(filename);
 
 
-procedure TJunkObject.OnFileEntry(Name: String; Offset, UncompressedSize,
+  if lenpth=0 then
+    exit(filename);
+
+  pthends:=false;  filenameends:=false;
+  if (lenpth>0) and (pth[lenpth] in ['/','\']) then
+    pthends:=true;
+
+  if (lenfn>0) and (filename[1] in ['/','\']) then
+    filenameends:=true;
+
+  if pthends and filenameends then
+      result:=copy(pth,1,lenpth-1)+filename
+  else
+    if pthends or filenameends then
+        result:=pth+filename
+    else
+       result:=pth+pathsep+filename;
+end;
+
+
+procedure TListObject.OnFileEntry(Name: String; Offset, UncompressedSize,
   ASection: Integer);
   ASection: Integer);
 begin
 begin
   Inc(Count);
   Inc(Count);
@@ -117,13 +164,64 @@ begin
   WriteLn(Name);
   WriteLn(Name);
 end;
 end;
 
 
+procedure TExtractAllObject.OnFileEntry(Name: String; Offset, UncompressedSize,
+  ASection: Integer);
+var mem : TMemoryStream;
+    s   : String;
+    len : integer;
+procedure wrpoint;
+begin
+      if lastone_was_point then
+        writeln;
+      lastone_was_point:=false;
+end;
+begin
+  len:=Length(Name);
+  if ((Len>0) and (name[len]='/')) then
+    exit; // directory or empty file
+
+  if (UncompressedSize=0) Then
+    begin
+      WrPoint;
+      Writeln(stderr,'Skipping empty file ',Name);
+      exit;
+    end;
+  if ((Len>0) and (name[1]=':')) then
+    begin
+      WrPoint;
+      Writeln(stderr,'Skipping internal file : ',Name);
+      exit;
+    end;
+  mem:=r.getobject(name);
+  if assigned(mem) then
+    begin
+      s:=craftpath(basedir,name);
+      ForceDirectories(extractfiledir(s));
+      try
+         mem.savetofile(s);
+         write('.');
+         lastone_was_point:=true;
+      except
+        on e : exception do
+          begin
+            WrPoint;
+            Writeln(Stderr,'Error saving ',name,' to ',s,'.'            );
+          end;
+       end;
+    end
+  else
+    begin
+      Writeln(Stderr,'Can''t extract ',name);
+    end;
+end;
+
 var donotpage:boolean=false;
 var donotpage:boolean=false;
 
 
 procedure ListChm(Const Name:string;Section:Integer);
 procedure ListChm(Const Name:string;Section:Integer);
 var
 var
   ITS: TITSFReader;
   ITS: TITSFReader;
   Stream: TFileStream;
   Stream: TFileStream;
-  JunkObject: TJunkObject;
+  JunkObject: TListObject;
 
 
 begin
 begin
   if not Fileexists(name) then
   if not Fileexists(name) then
@@ -133,7 +231,7 @@ begin
     end;
     end;
 
 
   Stream := TFileStream.Create(name, fmOpenRead);
   Stream := TFileStream.Create(name, fmOpenRead);
-  JunkObject := TJunkObject.Create;
+  JunkObject := TListObject.Create;
   JunkObject.Section:=Section;
   JunkObject.Section:=Section;
   JunkObject.Count:=0;
   JunkObject.Count:=0;
   JunkObject.DoNotPage:=DoNotPage;
   JunkObject.DoNotPage:=DoNotPage;
@@ -181,6 +279,94 @@ begin
     end;
     end;
 end;
 end;
 
 
+procedure ExtractFileAll(chm,dirto2:string);
+var
+  fs: TFileStream;
+  m : TMemoryStream;
+  r : TChmReader;
+  fl : boolean;
+  ListAll : TExtractAllObject;
+begin
+  if not Fileexists(chm) then
+    begin
+      writeln(stderr,' Can''t find file ',chm);
+      halt(1);
+    end;
+
+
+  if not directoryexists(dirto2) then
+    begin
+      fl:=false;
+      try
+        mkdir(dirto2);
+        fl:=directoryexists(dirto2);
+      except
+       on e : exception do ;
+       end;
+      if not fl then
+        begin
+          writeln(stderr,'Directory ',dirto2,' doesn''t exist, and trying to create it fails');
+          halt(1);
+        end;
+      end;
+
+
+  fs:=TFileStream.create(chm,fmOpenRead);
+  r:=TCHMReader.create(fs,true);
+  Listall:= TExtractAllObject.Create;
+  ListAll.basedir:=dirto2;
+  ListAll.r:=r;
+  ListAll.lastone_was_point:=false;
+  r.GetCompleteFileList(@ListAll.OnFileEntry);
+
+  r.free;
+end;
+
+procedure unblockchm(s:string);
+var f : file;
+begin
+ writeln('unblocking ',s);
+ assignfile(f,s+':Zone.Identifier');
+ rewrite(f,1);
+ truncate(f);
+ closefile(f);
+end;
+
+procedure populatefiles(files:TStringlist;filespec:string);
+var
+  searchResult : TSearchRec;
+begin
+ if FindFirst(filespec, faAnyFile, searchResult) = 0 then
+  begin
+    repeat
+      files.add(searchresult.name);
+    until FindNext(searchResult) <> 0;
+    // Must free up resources used by these successful finds
+    FindClose(searchResult);
+  end;
+end;
+
+procedure unblockchms(filespec:TStringDynArray);
+
+var files : TStringList;
+    i : Integer;
+
+begin
+ files :=TStringList.create;
+ try
+   for i:=0 to length(filespec)-1 do
+    populatefiles(files,filespec[i]);
+ except
+   writeln(stderr,'Error while scanning directory ',filespec[i]);
+   writeln(stderr,'Exiting....');
+   halt(1);
+  end;
+ if files.count>0 then
+   for i:=0 to files.count-1 do
+     unblockchm(files[i]);
+ Files.Free;
+end;
+
 procedure buildarglist(var params: TStringDynArray;var cmd :TCmdEnum);
 procedure buildarglist(var params: TStringDynArray;var cmd :TCmdEnum);
 
 
 var s           : ansistring;
 var s           : ansistring;
@@ -261,11 +447,7 @@ begin
                           ListChm(localparams[0],Section);
                           ListChm(localparams[0],Section);
                         end;
                         end;
                   else
                   else
-                    begin
-                      writeln(stderr,' Wrong number of parameters for LIST ',length(localparams));
-                      usage;
-                      halt(1);
-                    end
+                    WrongNrParam(cmdnames[cmd],length(localparams));
                    end; {case}
                    end; {case}
                 end; { cmdlist}
                 end; { cmdlist}
       cmdextract : begin
       cmdextract : begin
@@ -273,13 +455,23 @@ begin
                       2: ExtractFile(localparams[0],localparams[1],extractfilename(localparams[1]));
                       2: ExtractFile(localparams[0],localparams[1],extractfilename(localparams[1]));
                       3: ExtractFile(localparams[0],localparams[1],localparams[2]);
                       3: ExtractFile(localparams[0],localparams[1],localparams[2]);
                      else
                      else
-                      begin
-                        writeln(stderr,' Wrong number of parameters for LIST ',length(localparams));
-                        usage;
-                        halt(1);
-                      end
+                       WrongNrParam(cmdnames[cmd],length(localparams));
                      end;
                      end;
                    end;
                    end;
+      cmdextractall: begin
+                      if length(localparams)=2 then
+                        ExtractFileall(localparams[0],localparams[1])
+                      else
+                        WrongNrParam(cmdnames[cmd],length(localparams));
+                     end;
+
+      cmdunblock   : begin
+                      if length(localparams)>0 then
+                        Unblockchms(localparams)
+                      else
+                        WrongNrParam(cmdnames[cmd],length(localparams));
+                     end;
+
       end; {case cmd of}
       end; {case cmd of}
   end
   end
  else
  else

+ 9 - 16
packages/chm/src/chmreader.pas

@@ -268,15 +268,18 @@ end;
 
 
 procedure TChmReader.ReadCommonData;
 procedure TChmReader.ReadCommonData;
    // A little helper proc to make reading a null terminated string easier
    // A little helper proc to make reading a null terminated string easier
-   function ReadString(const Stream: TStream): String;
+   function ReadString(const Stream: TStream; StartPos: DWord; FixURL: Boolean): String;
    var
    var
      buf: array[0..49] of char;
      buf: array[0..49] of char;
    begin
    begin
      Result := '';
      Result := '';
+     Stream.Position := StartPos;
      repeat
      repeat
        Stream.Read(buf, 50);
        Stream.Read(buf, 50);
        Result := Result + buf;
        Result := Result + buf;
      until Pos(#0, buf) > -1;
      until Pos(#0, buf) > -1;
+     if FixURL then
+       Result := StringReplace(Result, '\', '/', [rfReplaceAll]);
    end;
    end;
    procedure ReadFromSystem;
    procedure ReadFromSystem;
    var
    var
@@ -373,7 +376,6 @@ procedure TChmReader.ReadCommonData;
      EntryCount,
      EntryCount,
      EntrySize: DWord;
      EntrySize: DWord;
      EntryStart: QWord;
      EntryStart: QWord;
-     StrPosition: DWord;
      X: Integer;
      X: Integer;
      OffSet: QWord;
      OffSet: QWord;
    begin
    begin
@@ -399,27 +401,19 @@ procedure TChmReader.ReadCommonData;
        EntryStart := OffSet + (X*EntrySize);
        EntryStart := OffSet + (X*EntrySize);
        if fTitle = '' then begin
        if fTitle = '' then begin
          fWindows.Position := EntryStart + $14;
          fWindows.Position := EntryStart + $14;
-         StrPosition := LEtoN(fWindows.ReadDWord);
-         fStrings.Position := StrPosition;
-         fTitle := '/'+ReadString(fStrings);
+         fTitle := '/'+ReadString(fStrings, LEtoN(fWindows.ReadDWord), False);
        end;
        end;
        if fTOCFile = '' then begin
        if fTOCFile = '' then begin
          fWindows.Position := EntryStart + $60;
          fWindows.Position := EntryStart + $60;
-         StrPosition := LEtoN(fWindows.ReadDWord);
-         fStrings.Position := StrPosition;
-         fTOCFile := '/'+ReadString(fStrings);
+         fTOCFile := '/'+ReadString(fStrings, LEtoN(fWindows.ReadDWord), True);
        end;
        end;
        if fIndexFile = '' then begin
        if fIndexFile = '' then begin
          fWindows.Position := EntryStart + $64;
          fWindows.Position := EntryStart + $64;
-         StrPosition := LEtoN(fWindows.ReadDWord);
-         fStrings.Position := StrPosition;
-         fIndexFile := '/'+ReadString(fStrings);
+         fIndexFile := '/'+ReadString(fStrings, LEtoN(fWindows.ReadDWord), True);
        end;
        end;
        if fDefaultPage = '' then begin
        if fDefaultPage = '' then begin
          fWindows.Position := EntryStart + $68;
          fWindows.Position := EntryStart + $68;
-         StrPosition := LEtoN(fWindows.ReadDWord);
-         fStrings.Position := StrPosition;
-         fDefaultPage := '/'+ReadString(fStrings);
+         fDefaultPage := '/'+ReadString(fStrings, LEtoN(fWindows.ReadDWord), True);
        end;
        end;
      end;
      end;
      ReadWindows(FWindows);
      ReadWindows(FWindows);
@@ -445,8 +439,7 @@ procedure TChmReader.ReadCommonData;
      while fIVB.Position < fIVB.Size do begin
      while fIVB.Position < fIVB.Size do begin
        Value := LEtoN(fIVB.ReadDWord);
        Value := LEtoN(fIVB.ReadDWord);
        OffSet := LEtoN(fIVB.ReadDWord);
        OffSet := LEtoN(fIVB.ReadDWord);
-       fStrings.Position := Offset;
-       Str := '/'+ReadString(fStrings);
+       Str := '/'+ ReadString(fStrings, Offset, True);
        fContextList.AddContext(Value, Str);
        fContextList.AddContext(Value, Str);
      end;
      end;
    end;
    end;

+ 11 - 2
packages/chm/src/chmwriter.pas

@@ -137,6 +137,7 @@ Type
     FDefaultFont: String;
     FDefaultFont: String;
     FDefaultPage: String;
     FDefaultPage: String;
     FFullTextSearch: Boolean;
     FFullTextSearch: Boolean;
+    FFullTextSearchAvailable: Boolean;
     FSearchTitlesOnly: Boolean;
     FSearchTitlesOnly: Boolean;
     FStringsStream: TMemoryStream; // the #STRINGS file
     FStringsStream: TMemoryStream; // the #STRINGS file
     FTopicsStream: TMemoryStream;  // the #TOPICS file
     FTopicsStream: TMemoryStream;  // the #TOPICS file
@@ -248,7 +249,7 @@ begin
     ITSFsig := ITSFFileSig;
     ITSFsig := ITSFFileSig;
     Version := NToLE(DWord(3));
     Version := NToLE(DWord(3));
     // we fix endian order when this is written to the stream
     // we fix endian order when this is written to the stream
-    HeaderLength := NToLE(DWord(SizeOf(TITSFHeader) + (SizeOf(TITSFHeaderEntry)*2) + SizeOf(TITSFHeaderSuffix)));
+    HeaderLength := NToLE(DWord(SizeOf(TITSFHeader) + (SizeOf(TGuid)*2)+ (SizeOf(TITSFHeaderEntry)*2) + SizeOf(TITSFHeaderSuffix)));
     Unknown_1 := NToLE(DWord(1));
     Unknown_1 := NToLE(DWord(1));
     TimeStamp:= NToBE(MilliSecondOfTheDay(Now)); //bigendian
     TimeStamp:= NToBE(MilliSecondOfTheDay(Now)); //bigendian
     LanguageID := NToLE(DWord($0409)); // English / English_US
     LanguageID := NToLE(DWord($0409)); // English / English_US
@@ -970,7 +971,7 @@ begin
 
 
   FSection0.WriteDWord(NToLE(DWord($0409)));
   FSection0.WriteDWord(NToLE(DWord($0409)));
   FSection0.WriteDWord(1);
   FSection0.WriteDWord(1);
-  FSection0.WriteDWord(NToLE(DWord(Ord(FFullTextSearch))));
+  FSection0.WriteDWord(NToLE(DWord(Ord(FFullTextSearch and FFullTextSearchAvailable))));
   FSection0.WriteDWord(0);
   FSection0.WriteDWord(0);
   FSection0.WriteDWord(0);
   FSection0.WriteDWord(0);
 
 
@@ -1256,6 +1257,14 @@ begin
   if FTopicsStream.Size = 0 then
   if FTopicsStream.Size = 0 then
     Exit;
     Exit;
   SearchWriter := TChmSearchWriter.Create(FFiftiMainStream, FIndexedFiles);
   SearchWriter := TChmSearchWriter.Create(FFiftiMainStream, FIndexedFiles);
+  // do not add an empty $FIftiMain
+  if not SearchWriter.HasData then
+  begin
+    FFullTextSearchAvailable := False;
+    SearchWriter.Free;
+    Exit;
+  end;
+  FFullTextSearchAvailable := True;
   SearchWriter.WriteToStream;
   SearchWriter.WriteToStream;
   SearchWriter.Free;
   SearchWriter.Free;
 
 

+ 508 - 0
packages/chm/src/itolitlsreader.pas

@@ -0,0 +1,508 @@
+{ Copyright (C) <2010> <Andrew Haines> itloitlsreader.pas
+
+  This library is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Library 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 Library General Public License
+  for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; if not, write to the Free Software Foundation,
+  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+}
+{
+  See the file COPYING.modifiedLGPL, included in this distribution,
+  for details about the copyright.
+}
+unit ITOLITLSReader;
+
+{$mode objfpc}{$H+}
+
+{ $DEFINE DEBUG_HELP2}
+
+interface
+
+uses
+  Classes, chmreader, itolitlstypes, Sysutils, chmbase, itsftransform;
+
+type
+
+  { TITOLITLSReader }
+
+  TITOLITLSReader = class(TITSFReader)
+  private
+    FStartStreamPos: QWord; // used when the data we are reading is part of a larger file
+    SectionNames: TStringList;
+    function GetStreamPos: Qword;
+    procedure SetStreamPos(const AValue: Qword);
+
+  private
+    Header: TITOLITLSHeader;
+    HeaderSectionTable: array of TITOLITLSHeaderSectionEntry;
+    PostHeader: TITOLITLSPostHeader;
+    CAOLHeader: TCAOLRec;
+    function FileSize: QWord;
+    function GetChunkType(AStream: TStream): TDirChunkType;
+    function GetTransform(const AGuid: TGuid): TITSFTransform;
+    procedure ReadHeader; override;
+    procedure ReadHeaderEntries; override;
+    function  GetTransforms(ASectionPrefix: String): TITSFTransformList;
+
+    property StreamPos: Qword read GetStreamPos write SetStreamPos;
+  public
+    constructor Create(AStream: TStream; FreeStreamOnDestroy: Boolean); override;
+    destructor Destroy; override;
+    procedure GetCompleteFileList(ForEach: TFileEntryForEach; AIncludeInternalFiles: Boolean = True); override;
+    function ObjectExists(Name: String): QWord; override;
+    function GetObject(Name: String): TMemoryStream; override;
+
+  end;
+
+implementation
+
+type
+
+  { TStreamChunk }
+
+  TStreamChunk = class(TStream)
+  private
+    FStream: TStream;
+    FSize: QWord;
+    FBasePos: QWord;
+    FPos: QWord;
+  public
+    Function GetSize : Int64; Override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    constructor Create(AHostStream: TStream; ABasePos, ASize: QWord);
+  end;
+
+{ TStreamChunk }
+
+function TStreamChunk.GetSize: Int64;
+begin
+  Result:=FSize;
+end;
+
+function TStreamChunk.Read(var Buffer; Count: Longint): Longint;
+begin
+  FStream.Seek(FBasePos+FPos, soFromBeginning);
+  {$IFDEF DEBUG_HELP2}
+  //WriteLn('Want Read Count: ', Count,' Pos = ', FPos);
+  //if FSize - FPos < Count then
+  //  Count := FSize - FPos;
+  {$ENDIF}
+  Result := FStream.Read(Buffer, Count);
+  Inc(FPos, Result);
+end;
+
+function TStreamChunk.Seek(Offset: Longint; Origin: Word): Longint;
+var
+  NewPosition: LongInt;
+begin
+  Case Origin of
+    soFromBeginning : NewPosition:=Offset;
+    soFromEnd       : NewPosition:=FSize+Offset;
+    soFromCurrent   : NewPosition:=NewPosition+Offset;
+  end;
+  {$IFDEF DEBUG_HELP2}
+  //WriteLn('WantSeek = ', Offset,' Size = ', FSize);
+  {$ENDIF}
+  FPos:=NewPosition;
+  Exit(NewPosition);
+  if NewPosition < 0 then NewPosition := 0;
+  if NewPosition >= FSize then NewPosition := FSize-1;
+  FStream.Position := FBasePos+NewPosition;
+  Result := FStream.Position - FBasePos;
+  FPos := Result;
+  {$IFDEF DEBUG_HELP2}
+  //WriteLn('Pos = ', fpos);
+  {$ENDIF}
+end;
+
+constructor TStreamChunk.Create(AHostStream: TStream; ABasePos, ASize: QWord);
+begin
+  FStream := AHostStream;
+  FBasePos := ABasePos;
+  FSize := ASize;
+  {$IFDEF DEBUG_HELP2}
+  //WriteLn('Created Size = ', FSize, ' Offset = ', ABasePos);
+  {$ENDIF}
+end;
+
+
+
+{ TITOLITLSReader }
+
+function TITOLITLSReader.GetStreamPos: Qword;
+begin
+  Result := fStream.Position-FStartStreamPos;
+end;
+
+procedure TITOLITLSReader.SetStreamPos(const AValue: Qword);
+begin
+  fStream.Position:=FStartStreamPos+AValue;
+end;
+
+function TITOLITLSReader.FileSize: QWord;
+begin
+  fStream.Position:=LEtoN(HeaderSectionTable[0].OffSet)+8;
+  fStream.Read(Result, 8);
+  Result := LEtoN(Result);
+end;
+
+function TITOLITLSReader.GetChunkType(AStream: TStream): TDirChunkType;
+var
+  Sig: TSig;
+begin
+  AStream.Read(Sig, 4);
+  if Sig = 'PMGL' then Result := ctPMGL
+  else if Sig = 'PMGI' then Result := ctPMGI
+  else if Sig = 'AOLL' then Result := ctAOLL
+  else if Sig = 'AOLI' then Result := ctAOLI;
+  AStream.Seek(-4,soFromCurrent);
+end;
+
+function TITOLITLSReader.GetTransform(const AGuid: TGuid): TITSFTransform;
+begin
+  Result := nil;
+end;
+
+procedure TITOLITLSReader.ReadHeader;
+var
+  CachedPos: QWord;
+  SectionName: string;
+  i: Integer;
+begin
+  {$IFDEF DEBUG_HELP2}
+  WriteLn(ClassName);
+  {$ENDIF}
+  fStream.Read(Header, SizeOf(TITOLITLSHeader));
+  if not((Header.Sig[0] = 'ITOL') and (Header.Sig[1] = 'ITLS')) then
+    Exit;
+  ReadHeaderEntries;
+  CachedPos := StreamPos;
+  fStream.Read(PostHeader, Sizeof(TITOLITLSPostHeader));
+  StreamPos := CachedPos + PostHeader.CAOLOffset;
+  fStream.Read(CAOLHeader, SizeOf(TCAOLRec));
+  {$IFDEF DEBUG_HELP2}
+  WriteLn(CAOLHeader.ITSFHeader.ITSFsig);
+  {$ENDIF}
+  GetSections(SectionNames);
+  for i := 1 to SectionNames.Count-1 do
+  begin
+    FmtStr(SectionName, '::DataSpace/Storage/%s/',[SectionNames[i]]);
+    SectionNames.Objects[i] := GetTransforms(SectionName);
+  end;
+end;
+
+procedure TITOLITLSReader.ReadHeaderEntries;
+var
+ i: Integer;
+begin
+  StreamPos := Header.HeaderSectionTableOffset;
+  SetLength(HeaderSectionTable, Header.HeaderSectionEntryCount);
+  for i := 0 to Header.HeaderSectionEntryCount -1 do
+  begin
+    fStream.Read(HeaderSectionTable[i], SizeOf(TITOLITLSHeaderSectionEntry));
+    HeaderSectionTable[i].OffSet:= LEtoN(HeaderSectionTable[i].OffSet);
+    HeaderSectionTable[i].Length:= LEtoN(HeaderSectionTable[i].Length);
+    {$IFDEF DEBUG_HELP2}
+    //WriteLn('Entry #',i,' Offset = ',Entry.OffSet,' Length = ',Entry.Length);
+    {$ENDIF}
+
+  end;
+end;
+
+function TITOLITLSReader.GetTransforms(ASectionPrefix: String): TITSFTransformList;
+var
+  Stream: TMemoryStream;
+  Guid: TGuid;
+  GCount: Integer;
+  Transform: TITSFTransform;
+  TransformClass: TITSFTransformClass = nil;
+  Idx: Integer;
+begin
+  Result := nil;
+  Stream := GetObject(ASectionPrefix+'Transform/List');
+  if Stream = nil then
+  begin
+    {$IFDEF DEBUG_HELP2}
+    //WriteLn(ASectionPrefix+'Transform/List doesnt exist!');
+    {$ENDIF}
+    Exit;
+  end;
+
+  Result := TITSFTransformList.Create;
+
+  FillChar(Guid, SizeOf(Guid), 0);
+  TransformClass := RegisteredTransforms.Transform[Guid];
+  Idx := Result.AddTransform(TransformClass);
+  Transform := TransformClass.Create(@Self.GetObject, nil);
+  Result.TransformInstance[Idx] := Transform;
+  {$IFDEF DEBUG_HELP2}
+  WriteLn('Sec: ', ASectionPrefix, ' Transform Add ', Transform.ClassName);
+  {$ENDIF}
+
+  GCount := Stream.Size div SizeOf(TGuid);
+  while GCount > 0 do
+  begin
+    Dec(GCount);
+    Stream.Read(Guid, 16);
+    TransformClass := RegisteredTransforms.Transform[Guid];
+    Idx := Result.AddTransform(TransformClass);
+    Transform := TransformClass.Create(@Self.GetObject, Transform);
+    Result.TransformInstance[Idx] := Transform;
+    {$IFDEF DEBUG_HELP2}
+    WriteLn('Sec: ', ASectionPrefix, ' Transform Add ', Transform.ClassName);
+    {$ENDIF}
+  end;
+  Stream.Free;
+end;
+
+constructor TITOLITLSReader.Create(AStream: TStream;
+  FreeStreamOnDestroy: Boolean);
+begin
+  inherited Create(AStream, FreeStreamOnDestroy);
+end;
+
+destructor TITOLITLSReader.Destroy;
+begin
+  if SectionNames<> nil then
+  begin
+    while SectionNames.Count > 0 do
+    begin
+     if SectionNames.Objects[SectionNames.Count-1] <> nil then
+       SectionNames.Objects[SectionNames.Count-1].Free;
+     SectionNames.Delete(SectionNames.Count-1);
+    end;
+    SectionNames.Free;
+  end;
+  inherited Destroy;
+end;
+
+function ReadEntry(AStream: TStream): TPMGListChunkEntry;
+var
+  NameLength: LongInt;
+begin
+  NameLength:=GetCompressedInteger(AStream);
+  SetLength(Result.Name, NameLength);
+  AStream.Read(Result.Name[1], NameLength);
+  Result.ContentSection:= GetCompressedInteger(AStream);
+  Result.ContentOffset:= GetCompressedInteger(AStream);
+  Result.DecompressedLength:= GetCompressedInteger(AStream);
+end;
+
+procedure TITOLITLSReader.GetCompleteFileList(ForEach: TFileEntryForEach; AIncludeInternalFiles: Boolean = True);
+var
+  SecOffset: QWord;
+  IFCM: TIFCMRec;
+  ChunkType: TDirChunkType;
+  Chunk: TMemoryStream;
+  i, j: Integer;
+  AOLL: TAOLLChunkHeader;
+  AOLI: TAOLIChunkHeader;
+  Entry: TPMGListChunkEntry;// not really a PMGL entry but the members are the same
+  NameLength: LongInt;
+  EntryCount: Word;
+begin
+  StreamPos:=HeaderSectionTable[1].OffSet;
+  fStream.Read(IFCM, SizeOf(IFCM));
+
+  for i := 0 to IFCM.ChunkCount-1 do
+  begin
+    Chunk:= TMemoryStream.Create;
+    Chunk.CopyFrom(fStream, IFCM.ChunkSize);
+    Chunk.Position:=0;
+
+    ChunkType:= GetChunkType(Chunk);
+    case ChunkType of
+      ctAOLL :
+      begin
+        Chunk.Read(AOLL, SizeOf(AOLL));
+        Chunk.Seek(-2, soFromEnd);
+        EntryCount:= LEtoN(Chunk.ReadWord);
+        {$IFDEF DEBUG_HELP2}
+        WriteLn(EntryCount);
+        {$ENDIF}
+        Chunk.Seek(SizeOf(AOLL), soFromBeginning);
+        for j := 0 to EntryCount-1 do
+        begin
+          Entry := ReadEntry(Chunk);
+          ForEach(Entry.Name, Entry.ContentOffset, Entry.DecompressedLength, Entry.ContentSection);
+        end;
+      end;
+      ctAOLI :
+      begin
+        //Chunk.Read(AOLI, SizeOf(AOLI));
+      end;
+    end;
+    Chunk.Free;
+  end;
+
+end;
+
+function TITOLITLSReader.ObjectExists(Name: String): QWord;
+var
+ IFCM: TIFCMRec;
+ ChunkIndex: QWord;
+ Chunk: TMemoryStream;
+ StartOfChunks: QWord;
+ EntryCount: Word;
+ AOLL: TAOLLChunkHeader;
+ AOLI: TAOLIChunkHeader;
+ Entry: TPMGListChunkEntry;
+ CRes: LongInt;
+ i: integer;
+begin
+  Result := 0;
+
+  if Name = fCachedEntry.Name then
+    Exit(fCachedEntry.DecompressedLength); // we've already looked it up
+
+  fCachedEntry.Name:='';
+  fCachedEntry.ContentSection:=-1;
+  fCachedEntry.DecompressedLength:=0;
+  fCachedEntry.ContentOffset:=-1;
+
+  StreamPos:=HeaderSectionTable[1].OffSet;
+  fStream.Read(IFCM, SizeOf(IFCM));
+  StartOfChunks := fstream.Position;
+  {$R-}
+  ChunkIndex:=PostHeader.ListChunkInfo.TopAOLIChunkIndex;
+  if ChunkIndex = -1 then
+    ChunkIndex := PostHeader.ListChunkInfo.FirstAOLLChunkIndex;
+
+  Chunk := TMemoryStream.Create;
+  while ChunkIndex <> -1 do
+  begin
+    Chunk.Position:=0;
+    fStream.Position:= StartOfChunks + (IFCM.ChunkSize*ChunkIndex);
+    Chunk.CopyFrom(fStream, IFCM.ChunkSize);
+    Chunk.Position:=0;
+
+    case GetChunkType(Chunk) of
+      ctAOLL :
+      begin
+        Chunk.Read(AOLL, SizeOf(AOLL));
+        Chunk.Seek(-2, soFromEnd);
+        EntryCount:= LEtoN(Chunk.ReadWord);
+        {$IFDEF DEBUG_HELP2}
+        WriteLn(EntryCount);
+        {$ENDIF}
+        Chunk.Seek(SizeOf(AOLL), soFromBeginning);
+        for i := 0 to EntryCount-1 do
+        begin
+          Entry := ReadEntry(Chunk);
+          CRes := ChmCompareText(Name, Entry.Name);
+          if CRes = 0 then
+          begin
+            ChunkIndex:=-1;
+            fCachedEntry := Entry;
+            Break;
+
+          end
+          else if CRes > 0 then
+            Continue
+          else
+          begin
+            ChunkIndex := -1;
+            Break;
+          end;
+        end;
+      end;
+      ctAOLI :
+      begin
+        //Chunk.Read(AOLI, SizeOf(AOLI));
+      end;
+    end;
+
+
+  end;
+  {$R+}
+  Chunk.Free;
+  Result := fCachedEntry.DecompressedLength;
+
+end;
+
+function TITOLITLSReader.GetObject(Name: String): TMemoryStream;
+var
+  Entry,
+  ContentEntry: TPMGListChunkEntry;
+  SectionName: String;
+  Transforms: TITSFTransformList;
+  Transform: TITSFTransform;
+  ContentStream: TStream;
+  ChunkPos: QWord;
+  i: Integer;
+begin
+  Result := nil;
+  {$IFDEF DEBUG_HELP2}
+  WriteLn('Want: ', Name);
+  {$ENDIF}
+  if ObjectExists(Name) = 0 then begin
+    //WriteLn('Object ', name,' Doesn''t exist or is zero sized.');
+    Exit;
+  end;
+  if Name = '/' then
+    Exit; // wierd bug where written size and offset contain random data
+  Entry := fCachedEntry;
+
+
+
+  if Entry.ContentSection = 0 then begin
+    Result := TMemoryStream.Create;
+    {$IFDEF DEBUG_HELP2}
+    WriteLn('Offset = ', Entry.ContentOffset);
+    {$ENDIF}
+    //StreamPos := CAOLHeader.ITSFHeader.Section0Offset + Entry.ContentOffset;
+    ChunkPos := CAOLHeader.ITSFHeader.Section0Offset;// + fCachedEntry.ContentOffset;
+    ContentStream := TStreamChunk.Create(fStream, ChunkPos, FileSize-ChunkPos);
+    ContentStream.Seek(Entry.ContentOffset, soFromBeginning);
+    Result.CopyFrom(ContentStream, Entry.DecompressedLength);
+    ContentStream.Free;
+
+  end
+  else
+  begin
+    FmtStr(SectionName, '::DataSpace/Storage/%s/',[SectionNames[Entry.ContentSection]]);
+    {$IFDEF DEBUG_HELP2}
+    WriteLn('Want: ', SectionName);
+    {$ENDIF}
+    if ObjectExists(SectionName+'Content') = 0 then
+      Exit;
+    ContentEntry := fCachedEntry;
+
+    Transforms := TITSFTransformList(SectionNames.Objects[Entry.ContentSection]);
+    if Transforms = nil then
+      Exit;
+    ChunkPos := CAOLHeader.ITSFHeader.Section0Offset + ContentEntry.ContentOffset;
+    ContentStream := TStreamChunk.Create(fStream, ChunkPos, ContentEntry.DecompressedLength);
+    //ContentStream := GetObject(SectionName+'Content');
+    Result := TMemoryStream.Create;
+    {$IFDEF DEBUG_HELP2}
+    {for i := Transforms.Count-1 downto 0 do
+    begin
+        //WriteLn('Found Transform: ', GUIDToString(Transforms.TransformIndex[i].GUID));
+
+        //WriteLn(Transform.ClassName);
+        Transform := Transforms.TransformInstance[i];
+        if Transform = nil then
+          WriteLn('Trqansform = nil!');
+
+    end;}
+
+    WriteLn('Transform Count = ', Transforms.Count);
+    WriteLn('Asking ', Transforms.TransformInstance[Transforms.Count-1].ClassName,' for data');
+    {$ENDIF}
+    Transforms.TransformInstance[Transforms.Count-1].WantData(SectionName, ContentStream, Entry.ContentOffset, Entry.DecompressedLength, Result);
+    ContentStream.Free;
+  end;
+  Result.Position := 0;
+end;
+
+end.

+ 157 - 0
packages/chm/src/itolitlstypes.pas

@@ -0,0 +1,157 @@
+{ Copyright (C) <2010> <Andrew Haines> itolitlstypes.pas
+
+  This library is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Library 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 Library General Public License
+  for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; if not, write to the Free Software Foundation,
+  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+}
+{
+  See the file COPYING.modifiedLGPL, included in this distribution,
+  for details about the copyright.
+}
+unit ITOLITLSTypes;
+
+{$mode objfpc}{$H+}
+{$PACKRECORDS C}
+
+interface
+
+uses ChmBase;
+
+type
+
+  TSig = array[0..3] of char;
+  TITOLITLSHeader = record
+   Sig: Array [0..1] of TSig; //  ITLO/ITLS
+   Version: DWord; // = 1
+   HeaderSectionTableOffset: DWord;
+   HeaderSectionEntryCount: DWord;
+   PostHeaderTableSize: DWord;
+   GUID: TGuid; // {0A9007C1-4076-11D3-8789-0000F8105754}
+  end;
+
+  TITOLITLSHeaderSectionEntry = record
+    OffSet: QWord; // From Start of ITLO/ITLS
+    Length: QWord;
+  end;
+
+  TChunkDirInfo = record
+    TopAOLIChunkIndex: QWord; // -1 if none
+    FirstAOLLChunkIndex,
+    LastAOLLChunkIndex: QWord;
+    Unknown0: QWord; // 0
+    ChunkSize: DWord; // = $2000 if list $200 if Index
+    QuickRefDensity: DWord; // = 2
+    Unknown1: DWord; // = 0
+    DirDepth: DWord; // 1 there is no index, 2 if there is one level of AOLI 3 if two index levels etc
+    Unknown2: QWord; // 0
+    DirEntryCount: QWord; // Number Of Directory Entries
+  end;
+
+  TITSFHeaderV4= record
+    ITSFsig: array [0..3] of char;
+    Version: LongWord;
+    HeaderLength: LongWord;
+    Unknown_1: LongWord;
+    Section0Offset: QWord;
+    TimeStamp: LongWord; //bigendian
+    LanguageID: LongWord;
+  end;
+
+  TCAOLRec = record
+    Sig: TSig; // CAOL
+    Version: DWord; // 2
+    CAOLSize: DWord; // includes ITSF section = $50
+    CompilerID: array [0..1] of char; // = "HH"
+    Unknown: Word; // 0
+    Unknown1: DWord; // $43ED or 0
+    DirChunkSize: DWord; // $2000
+    DirIndexChunkSize: DWord; // $200
+    Unknown2,       // $100000
+    Unknown3: DWord;// $20000
+    Unknown4,
+    Unknown5,
+    Unknown6: DWord; // = 0
+    ITSFHeader: TITSFHeaderV4;
+  end;
+
+  TITOLITLSPostHeader = record
+    Version: DWord; // 2
+    CAOLOffset: DWord; // usually $98 (is from start of PostHeader)
+    ListChunkInfo,
+    IndexChunkInfo: TChunkDirInfo;
+    Unknown3: DWord; // = $100000
+    Unknown4: Dword; // =  $20000
+    Unknown5: QWord; // 0
+
+  end;
+
+  THeaderSection0 = TITSPHeaderPrefix;
+
+  TIFCMRec = record
+    SIG: TSig; // = IFCM
+    Version: DWord; // = 1
+    ChunkSize: DWord; // = $2000
+    UnKnown: DWord; // = $100000
+    Unknown1: DWord; // = -1
+    Unknown2: DWord; // = -1
+    ChunkCount: Dword;//
+    Unknown3: DWord; // = 0
+  end;
+
+  TAOLLChunkHeader = record
+    Sig: TSig; // = AOLL
+    QuickRefSize: DWord;
+    ChunkIndex: QWord; // must be correct in the order written
+    PrevChunkIndex: QWord;
+    NextChunkIndex: QWord;
+    FirstEntryIndex: QWord;
+    Unknown0,       // = 1
+    Unknown1: DWord;// = 0
+    // entries
+  end;
+
+  TAOLIChunkHeader = record
+   Sig: TSig; // = AOLI
+   QuickRefSize: DWord;//    Length of quickref area at end of directory chunk
+   ChunkIndex: QWord;//    Directory chunk number
+   // entries
+  end;
+
+  const
+    ITOLITLSGuid: TGuid = '{0A9007C1-4076-11D3-8789-0000F8105754}';
+
+  type
+  TLZXv3ControlData = record
+    Sig: TSig;
+    Version: DWord;
+    ResetInterval: Dword;
+    WindowSize: DWord;
+    CacheSize: Dword;
+    Unknown1,
+    Unknown2: DWord; // 0
+  end;
+
+  TLZXv3ResetTable = record
+    Version: Dword;
+    EntryCount: DWord;
+    EntrySize: DWord;
+    EntryStart: DWord;
+    UnCompressedSize,
+    CompressedSize: QWord;
+    BlockSize: QWord; // $8000
+  end;
+
+
+implementation
+
+end.

+ 442 - 0
packages/chm/src/itsftransform.pas

@@ -0,0 +1,442 @@
+{ Copyright (C) <2010> <Andrew Haines> itfstransform.pas
+
+  This library is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Library 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 Library General Public License
+  for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; if not, write to the Free Software Foundation,
+  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+}
+{
+  See the file COPYING.modifiedLGPL, included in this distribution,
+  for details about the copyright.
+}
+unit ITSFTransform;
+
+{ $DEFINE DEBUG_HELP2}
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, paslzx, ITOLITLSTypes;
+
+type
+  TGetObject = function(AName: String): TMemoryStream of object;
+
+  TITSFTransformList = class;
+  TITSFTransform = class;
+
+  { TITSFTransform }
+  TITSFTransform = class
+  private
+    FDataStream: TStream;
+    FPrefix: String;
+    FParentTransform: TITSFTransform;
+  public
+    GetObject: TGetObject; // GetObject(Name: String): TMemoryStream;
+    OutStream: TMemoryStream;
+    constructor Create(AGetObject: TGetObject; AParentTransform: TITSFTransform); virtual;
+
+    function WantData(APrefix: String; ADataStream: TStream; const DataStart, DataLength: Integer; AOutStream: TMemoryStream): Boolean; virtual;
+
+    property ParentTransform : TITSFTransform read FParentTransform;
+    property Prefix: String read FPrefix write FPrefix;
+    property DataStream: TStream read FDataStream write FDataStream;
+    class function GUID: TGuid; virtual;
+    class function GUIDString: String; virtual;
+  end;
+
+  TITSFTransformClass = class of TITSFTransform;
+
+  { TPlainTransform }
+
+  TPlainTransform = class(TITSFTransform)
+    function WantData(APrefix: String; ADataStream: TStream; const DataStart, DataLength: Integer; AOutStream: TMemoryStream): Boolean; override;
+  end;
+
+  { TLZXv3Transform }
+
+  TLZXv3Transform = class(TITSFTransform)
+  private
+    Entries: array of QWord;
+    Data: TLZXv3ControlData;
+    Table: TLZXv3ResetTable;
+    function GetControlData: Boolean;
+    function GetResetTable: Boolean;
+
+    function FindChunkCompressedSize(AEntryIndex: Integer): DWord;
+    function FindFirstChunkFromOffset(AOffset, ASize: QWord; out ChunkCount: DWord): Integer;
+
+    function ExtractChunks(AFirstChunkIndex, AChunkCount: DWord; out ExtractedOffsetStart: QWord): TMemoryStream;
+  public
+    function WantData(APrefix: String; ADataStream: TStream; const DataStart, DataLength: Integer; AOutStream: TMemoryStream): Boolean; override;
+
+    class function GUID: TGuid; override;
+  end;
+
+  { TITSFTransformList }
+
+  TITSFTransformList = class(TFPList)
+  private
+    function GetTransform(AGuid: TGuid): TITSFTransformClass;
+    function GetTransformIndex(AIndex: DWord): TITSFTransformClass;
+    function GetTransformInstance(AIndex: DWord): TITSFTransform;
+    procedure SetTransformInstance(AIndex: DWord; const AValue: TITSFTransform);
+  public
+    function AddTransform(ATransform: TITSFTransformClass): Integer;
+    procedure Delete(AIndex: Integer);
+    property Transform[AGuid: TGuid]: TITSFTransformClass read GetTransform;
+    property TransformIndex[AIndex: DWord]: TITSFTransformClass read GetTransformIndex;
+    property TransformInstance[AIndex: DWord]: TITSFTransform read GetTransformInstance write SetTransformInstance;
+  end;
+
+function RegisteredTransforms: TITSFTransformList;
+
+
+implementation
+uses
+  SysUtils;
+
+var
+  LocTransforms: TITSFTransformList = nil;
+
+type
+  PITSFTranformItem = ^TITSFTranformItem;
+  TITSFTranformItem = record
+    //Guid: TGuid;
+    Transform: TITSFTransformClass;
+    Instance: TITSFTransform;
+  end;
+
+function RegisteredTransforms: TITSFTransformList;
+begin
+  if LocTransforms = nil then
+    LocTransforms := TITSFTransformList.Create;
+  Result := LocTransforms;
+end;
+
+{ TITSFTransform }
+
+constructor TITSFTransform.Create(AGetObject: TGetObject; AParentTransform: TITSFTransform);
+begin
+  GetObject:=AGetObject;
+  FParentTransform := AParentTransform;
+end;
+
+function TITSFTransform.WantData(APrefix: String; ADataStream: TStream;
+  const DataStart, DataLength: Integer; AOutStream: TMemoryStream): Boolean;
+begin
+  Prefix := APrefix;
+  DataStream := ADataStream;
+  OutStream := AOutStream;
+  {$IFDEF DEBUG_HELP2}
+  WriteLn('WantData Class = ', ClassName);
+  {$ENDIF}
+end;
+
+class function TITSFTransform.GUID: TGuid;
+const
+  AGuid: TGuid = '{00000000-0000-0000-0000-000000000000}';
+begin
+  Result := AGuid;
+end;
+
+class function TITSFTransform.GUIDString: String;
+begin
+  Result := GUIDToString(GUID);
+end;
+
+{ TITSFTransformList }
+
+function TITSFTransformList.GetTransform(AGuid: TGuid): TITSFTransformClass;
+var
+  Item: PITSFTranformItem;
+  i: Integer;
+  GUID: TGuid;
+begin
+  Result := nil;
+  for i := 0 to Count-1 do
+  begin
+    Item := PITSFTranformItem(Items[i]);
+    GUID := Item^.Transform.GUID;
+    if CompareByte(GUID,AGuid, 16) = 0 then
+      Exit(Item^.Transform);
+  end;
+end;
+
+function TITSFTransformList.GetTransformIndex(AIndex: DWord): TITSFTransformClass;
+begin
+  Result := PITSFTranformItem(Items[AIndex])^.Transform;
+end;
+
+function TITSFTransformList.GetTransformInstance(AIndex: DWord): TITSFTransform;
+begin
+  Result := PITSFTranformItem(Items[AIndex])^.Instance;
+end;
+
+procedure TITSFTransformList.SetTransformInstance(AIndex: DWord;
+  const AValue: TITSFTransform);
+begin
+  PITSFTranformItem(Items[AIndex])^.Instance := AValue;
+end;
+
+function TITSFTransformList.AddTransform(ATransform: TITSFTransformClass): Integer;
+var
+  Item: PITSFTranformItem;
+begin
+  if not Assigned(ATransform) then
+    Exit;
+  New(Item);
+  Item^.Transform:= ATransform;
+  Item^.Instance := nil;
+  Add(Item);
+end;
+
+procedure TITSFTransformList.Delete(AIndex: Integer);
+var
+  Item: PITSFTranformItem;
+begin
+  Item := PITSFTranformItem(Items[AIndex]);
+  Dispose(Item);
+  Inherited Delete(AIndex);
+end;
+
+{ TLZXv3Transform }
+
+function TLZXv3Transform.FindFirstChunkFromOffset(AOffset, ASize: QWord; out ChunkCount: DWord): Integer;
+var
+  EndChunk: DWord;
+begin
+  Result := AOffset div Table.BlockSize;
+  EndChunk := (AOffset + ASize) div Table.BlockSize;
+  ChunkCount:=EndChunk-Result;
+  //if ChunkCount = 0 then
+    Inc(ChunkCount);
+end;
+
+function TLZXv3Transform.GetControlData: Boolean;
+var
+  ControlDataStream: TStream;
+  ESize: LongWord;
+begin
+  Result := False;
+  try
+    ControlDataStream := GetObject(Prefix+'ControlData');
+
+    if ControlDataStream = nil then
+      Exit;
+
+
+    ESize := NtoLE(ControlDataStream.ReadDWord);
+    while ESize <> 7 do
+    begin
+      ControlDataStream.Seek(ESize*4, soFromCurrent);
+      ESize := LEtoN(ControlDataStream.ReadDWord);
+    end;
+    if ESize = 7 then
+      ControlDataStream.Read(Data, SizeOf(TLZXv3ControlData));
+
+  finally
+    if Assigned(ControlDataStream) then
+      ControlDataStream.Free;
+  end;
+  Result := ESize = 7;
+  //WriteLn('GetControlData = ', REsult);
+
+end;
+
+function TLZXv3Transform.GetResetTable: Boolean;
+var
+  WholePrefix: String;
+  ResetStream: TStream;
+  {$IFDEF ENDIAN_BIG}
+  i: Integer;
+  {$ENDIF}
+begin
+  Result := False;
+  WholePrefix:=Prefix+'Transform/'+GUIDString+'/';
+  ResetStream := GetObject(WholePrefix+'InstanceData/ResetTable');
+  if ResetStream = nil then
+    Exit;
+  ResetStream.Read(Table, SizeOf(TLZXv3ResetTable));
+  SetLength(Entries, Table.EntryCount);
+  ResetStream.Read(Entries[0], Table.EntryCount*8);
+  {$IFDEF ENDIAN_BIG}
+  for i := Low(Entries) to High(Entries) do
+    Entries[i] := LEtoN(Entries[i]);
+  {$ENDIF}
+  {$IFDEF DEBUG_HELP2}
+  //for i := Low(Entries) to High(Entries) do
+  //  WriteLn('Entry[',i,'] = ',Entries[i] ,' UnCompressStart = ', i*$8000);
+  {$ENDIF}
+  ResetStream.Free;
+
+  Result := True;
+end;
+
+function TLZXv3Transform.FindChunkCompressedSize(AEntryIndex: Integer): DWord;
+begin
+  if AEntryIndex < High(Entries) then
+    Result := Entries[AEntryIndex+1] - Entries[AEntryIndex]
+  else
+    Result := DataStream.Size-Entries[AEntryIndex];
+end;
+
+function TLZXv3Transform.ExtractChunks(AFirstChunkIndex, AChunkCount: DWord;
+  out ExtractedOffsetStart: QWord): TMemoryStream;
+var
+  LZX: PLZXState;
+  CStart,
+  CSize: DWord;
+  //CBuf: Pointer;
+  Buf: TMemoryStream;
+  CBuf: Pointer;
+  UBuf: Pointer;
+  USize: Dword;
+  URes: DWord;
+  WinCode: DWord;
+  WinSize: QWord;
+  BlockMask: Byte;
+begin
+  BlockMask := (Data.ResetInterval shl 1) - 1;
+
+  // must start on a even numbered block
+  while (AFirstChunkIndex mod Data.ResetInterval <> 0) and (AFirstChunkIndex > 0) do
+  begin
+    Dec(AFirstChunkIndex);
+    Inc(AChunkCount);
+  end;
+
+  ExtractedOffsetStart := Table.BlockSize*AFirstChunkIndex;
+
+  {$IFDEF DEBUG_HELP2}
+  WriteLn('Getting Data, StartChunk=', AFirstChunkIndex,' Count = ', AChunkCount);
+  WriteLn('Version = ', Data.Version);
+  WriteLn('Window Size = ',Data.WindowSize);
+  WriteLn('Block Size = ',Hexstr(Table.BlockSize,16));
+  WriteLn('Block Size = ',Table.BlockSize);
+  {$ENDIF}
+
+  WinSize := (Data.WindowSize * Table.BlockSize);
+  WinCode := 0;
+  while WinSize > 1 do
+  begin
+    Inc(WinCode);
+    //WriteLn(HexStr(WinSize, 16));
+    WinSize := WinSize shr 1;
+  end;
+
+  LZX := LZXinit(WinCode);//ata.WindowSize);
+
+  CBuf := GetMem(Table.BlockSize);
+  UBuf := GetMem(Table.BlockSize);
+
+  Result := TMemoryStream.Create;
+  Buf := TMemoryStream.Create;
+
+  CStart := Entries[AFirstChunkIndex];
+  CSize  := Entries[AFirstChunkIndex+AChunkCount]+FindChunkCompressedSize(AFirstChunkIndex+AChunkCount);
+  ParentTransform.WantData(Prefix, DataStream, CStart, CSize, Buf);
+  Buf.Position:=0;
+
+  while AChunkCount > 0 do
+  begin
+    Dec(AChunkCount);
+
+    CSize  := FindChunkCompressedSize(AFirstChunkIndex);
+
+    CSize := Buf.Read(CBuf^, CSize);
+    if AFirstChunkIndex mod Data.ResetInterval = 0 then
+    begin
+      LZXreset(LZX);
+      {$IFDEF DEBUG_HELP2}
+      WriteLn('Reset LZX Window');
+      {$ENDIF}
+    end;
+    URes := LZXdecompress(LZX, CBuf, UBuf, CSize, Table.BlockSize);
+    //CBuf.Size := 0;
+    {$IFDEF DEBUG_HELP2}
+    WriteLn('Decompress = ', URes);
+    {$ENDIF}
+
+    Result.Write(UBuf^, Table.BlockSize);
+    Inc(AFirstChunkIndex);
+  end;
+  Buf.Free;
+  Freemem(UBuf);
+  Freemem(CBuf);
+  Result.Position:=0;
+  LZXteardown(LZX);
+end;
+
+
+function TLZXv3Transform.WantData(APrefix: String; ADataStream: TStream; const DataStart,
+  DataLength: Integer; AOutStream: TMemoryStream): Boolean;
+var
+  LZXData: TLZXv3ControlData;
+  ResetTable: TLZXv3ResetTable;
+  ChunkStart,
+  ChunkCount: DWord;
+  RawChunks: TStream;
+  ChunkDataStart: QWord;
+begin
+  inherited WantData(APrefix, ADataStream, DataStart, DataLength, AOutStream);
+  {$IFDEF DEBUG_HELP2}
+  WriteLn('WantData Pre=',APrefix,' DS=', DataStart,' DL=',DataLength);
+  {$ENDIF}
+
+  Result := False;
+  if not (GetControlData and GetResetTable) then
+    Exit;
+  {$IFDEF DEBUG_HELP2}
+  WriteLn('Got Needed Info');
+  {$ENDIF}
+  ChunkStart := FindFirstChunkFromOffset(DataStart,DataLength, ChunkCount);
+
+  RawChunks := ExtractChunks(ChunkStart, ChunkCount, ChunkDataStart);
+
+  RawChunks.Position := DataStart-ChunkDataStart;
+  AOutStream.CopyFrom(RawChunks, DataLength);
+  RawChunks.Free;
+
+  Result := True;
+end;
+
+class function TLZXv3Transform.GUID: TGuid;
+const
+  AGuid: TGuid = '{0A9007C6-4076-11D3-8789-0000F8105754}';
+begin
+  Result := AGuid;
+end;
+
+{ TPlainTransform }
+
+function TPlainTransform.WantData(APrefix: String; ADataStream: TStream; const DataStart, DataLength: Integer;
+  AOutStream: TMemoryStream): Boolean;
+begin
+  inherited WantData(APrefix, ADataStream, DataStart, DataLength, AOutStream);
+  ADataStream.Position:=DataStart;
+  AOutStream.CopyFrom(ADataStream, DataLength);
+  Result := True;
+end;
+
+initialization
+  RegisteredTransforms.AddTransform(TPlainTransform);
+  RegisteredTransforms.AddTransform(TLZXv3Transform);
+
+finalization
+  if Assigned(LocTransforms) then
+    LocTransforms.Free;
+
+end.
+
+

+ 0 - 65
packages/chm/src/unblockchm.pp

@@ -1,65 +0,0 @@
-program unblockchm;
-
-// Marco van de Voort
-// BSD license 
-// Quick and dirty scritp to unblocks CHMs on xpsp2/vista/w7
-//
-// todo : populatefiles needs fix for when filespec contains a directory.
-//
-// based on http://stackoverflow.com/questions/1617509/unblock-a-file-with-powershell
-
-{$mode delphi}
-uses sysutils,classes;
-
-procedure usage;
-
-begin
-  writeln('unblockchm. Unblocks chms in XPsp2,vista,w7  (C) 2010 Marco van de Voort');
-  writeln;
-  Writeln('usage: unblockchm <filespec> <filespec2> ..');
-  writeln;
-  writeln('<filespec> may contain basic wildcards.');
-  writeln;
-end;
-
-procedure unblockchm(s:string);
-var f : file;
-begin
- writeln('unblocking ',s);
- assignfile(f,s+':Zone.Identifier');
- rewrite(f,1);
- truncate(f);
- closefile(f);
-end;
-
-procedure populatefiles(files:TStringlist;filespec:string);
-var
-  searchResult : TSearchRec;
-begin
- if FindFirst(filespec, faAnyFile, searchResult) = 0 then
-  begin
-    repeat
-      files.add(searchresult.name);
-    until FindNext(searchResult) <> 0;
-    // Must free up resources used by these successful finds
-    FindClose(searchResult);
-  end;
-end;
-
-var files : TStringList;
-    i : Integer;
-
-begin
- if paramcount=0 then
-   begin
-     Usage;
-     halt;
-   end;
- files :=TStringList.create;
- for i:=1 to paramcount do
-  populatefiles(files,paramstr(i));
- if files.count>0 then
-   for i:=0 to files.count-1 do
-     unblockchm(files[i]);
-end.
-

+ 76 - 35
packages/fcl-passrc/src/pastree.pp

@@ -67,8 +67,8 @@ resourcestring
   SPasTreeDestructorImpl = 'destructor implementation';
   SPasTreeDestructorImpl = 'destructor implementation';
 
 
 type
 type
-  TPasExprKind = (pekIdent, pekNumber, pekString, pekSet,
-     pekPrefix, pekPostfix, pekBinary, pekFuncParams, pekArrayParams);
+  TPasExprKind = (pekIdent, pekNumber, pekString, pekSet, pekRange,
+     pekUnary, pekBinary, pekFuncParams, pekArrayParams);
 
 
   TExprOpCode = (eopNone,
   TExprOpCode = (eopNone,
                  eopAdd,eopSubtract,eopMultiply,eopDivide, eopDiv,eopMod, eopPower,// arithmetic
                  eopAdd,eopSubtract,eopMultiply,eopDivide, eopDiv,eopMod, eopPower,// arithmetic
@@ -79,24 +79,45 @@ type
                  eopIn,eopIs,eopAs, eopSymmetricaldifference, // Specials
                  eopIn,eopIs,eopAs, eopSymmetricaldifference, // Specials
                  eopAddress);
                  eopAddress);
   
   
-  { TPasExprPart }
+  { TPasExpr }
 
 
-  TPasExprPart = class 
+  TPasExpr = class
     Kind      : TPasExprKind;
     Kind      : TPasExprKind;
-    Left      : TPasExprPart;
-    Right     : TPasExprPart;
     OpCode    : TexprOpcode;
     OpCode    : TexprOpcode;
-    Value    : AnsiString;
-    Params    : array of TPasExprPart;
-    constructor Create(AKind: TPasExprKind);
-    constructor CreateWithText(AKind: TPasExprKind; const AValue : Ansistring);
-    constructor CreatePrefix(rightExp: TPasExprPart; const AOpCode: TExprOpCode);
-    constructor CreatePostfix(leftExp: TPasExprPart; const AOpCode: TExprOpCode);
-    constructor CreateBinary(xleft, xright: TPasExprPart; const AOpCode: TExprOpCode);
+    constructor Create(AKind: TPasExprKind; AOpCode: TexprOpcode);
+  end;
+
+  TUnaryExpr = class(TPasExpr)
+    Operand   : TPasExpr;
+    constructor Create(AOperand: TPasExpr; AOpCode: TExprOpCode);
     destructor Destroy; override;
     destructor Destroy; override;
-    procedure AddParam(xp: TPasExprPart);
   end;
   end;
 
 
+  { TBinaryExpr }
+
+  TBinaryExpr = class(TPasExpr)
+    left      : TPasExpr;
+    right     : TPasExpr;
+    constructor Create(xleft, xright: TPasExpr; AOpCode: TExprOpCode);
+    constructor CreateRange(xleft, xright: TPasExpr);
+    destructor Destroy; override;
+  end;
+
+  TPrimitiveExpr = class(TPasExpr)
+    Value     : AnsiString;
+    constructor Create(AKind: TPasExprKind; const AValue : Ansistring);
+  end;
+
+  { TParamsExpr }
+
+  TParamsExpr = class(TPasExpr)
+    Value     : TPasExpr;
+    Params    : array of TPasExpr;
+    {pekArray, pekFuncCall, pekSet}
+    constructor Create(AKind: TPasExprKind);
+    destructor Destroy; override;
+    procedure AddParam(xp: TPasExpr);
+  end;
 
 
   // Visitor pattern.
   // Visitor pattern.
   TPassTreeVisitor = class;
   TPassTreeVisitor = class;
@@ -467,7 +488,7 @@ type
     Value: string;
     Value: string;
     Modifiers : string;
     Modifiers : string;
     AbsoluteLocation : String;
     AbsoluteLocation : String;
-    Expr: TPasExprPart;
+    Expr: TPasExpr;
   end;
   end;
 
 
   { TPasConst }
   { TPasConst }
@@ -2315,52 +2336,61 @@ begin
   Result:=true;
   Result:=true;
 end;
 end;
 
 
-{ TPasExprPart }
+{ TPasExpr }
 
 
-constructor TPasExprPart.Create(AKind:TPasExprKind);
+constructor TPasExpr.Create(AKind: TPasExprKind; AOpCode: TexprOpcode);
 begin
 begin
   Kind:=AKind;
   Kind:=AKind;
+  OpCode:=AOpCode;
 end;
 end;
 
 
-constructor TPasExprPart.CreateWithText(AKind:TPasExprKind;const AValue: AnsiString);
+{ TPrimitiveExpr }
+
+constructor TPrimitiveExpr.Create(AKind: TPasExprKind; const AValue : Ansistring);
 begin
 begin
-  Create(AKind);
+  inherited Create(AKind, eopNone);
   Value:=AValue;
   Value:=AValue;
 end;
 end;
 
 
-constructor TPasExprPart.CreatePrefix(rightExp: TPasExprPart; const AOpCode: TExprOpCode);
+{ TUnaryExpr }
+
+constructor TUnaryExpr.Create(AOperand: TPasExpr; AOpCode: TExprOpCode);
 begin
 begin
-  Create(pekPrefix);
-  right:=rightExp;
-  Opcode:=AOpCode;
+  inherited Create(pekUnary, AOpCode);
+  Operand:=AOperand;
 end;
 end;
 
 
-constructor TPasExprPart.CreatePostfix(leftExp: TPasExprPart; const AOpCode: TExprOpCode);
+destructor TUnaryExpr.Destroy;
 begin
 begin
-  Create(pekPostfix);
-  left:=leftExp;
-  Opcode:=AOpCode;
+  Operand.Free;
 end;
 end;
 
 
-constructor TPasExprPart.CreateBinary(xleft, xright: TPasExprPart; const AOpCode: TExprOpcode);
+{ TBinaryExpr }
+
+constructor TBinaryExpr.Create(xleft,xright:TPasExpr; AOpCode:TExprOpCode);
 begin
 begin
-  Create(pekBinary);
+  inherited Create(pekBinary, AOpCode);
   left:=xleft;
   left:=xleft;
   right:=xright;
   right:=xright;
-  Opcode:=AOpCode;
 end;
 end;
 
 
-destructor TPasExprPart.Destroy;
-var
-  i : Integer;
+constructor TBinaryExpr.CreateRange(xleft,xright:TPasExpr);
+begin
+  inherited Create(pekRange, eopNone);
+  left:=xleft;
+  right:=xright;
+end;
+
+destructor TBinaryExpr.Destroy;
 begin
 begin
   left.Free;
   left.Free;
   right.Free;
   right.Free;
-  for i:=0 to length(Params)-1 do Params[i].Free;
   inherited Destroy;
   inherited Destroy;
 end;
 end;
 
 
-procedure TPasExprPart.AddParam(xp:TPasExprPart);
+{ TParamsExpr }
+
+procedure TParamsExpr.AddParam(xp:TPasExpr);
 var
 var
   i : Integer;
   i : Integer;
 begin
 begin
@@ -2369,6 +2399,17 @@ begin
   Params[i]:=xp;
   Params[i]:=xp;
 end;
 end;
 
 
+constructor TParamsExpr.Create(AKind: TPasExprKind);
+begin
+  inherited Create(AKind, eopNone)
+end;
 
 
+destructor TParamsExpr.Destroy;
+var
+  i : Integer;
+begin
+  for i:=0 to length(Params)-1 do Params[i].Free;
+  inherited Destroy;
+end;
 
 
 end.
 end.

+ 76 - 72
packages/fcl-passrc/src/pparser.pp

@@ -45,6 +45,7 @@ resourcestring
   SParserInterfaceTokenError = 'Invalid token in interface section of unit';
   SParserInterfaceTokenError = 'Invalid token in interface section of unit';
   SParserImplementationTokenError = 'Invalid token in implementation section of unit';
   SParserImplementationTokenError = 'Invalid token in implementation section of unit';
   SParserInvalidTypeDef = 'Invalid type definition';
   SParserInvalidTypeDef = 'Invalid type definition';
+  SParserExpectedIdentifier = 'Identifier expected';
 
 
 type
 type
   TPasTreeContainer = class
   TPasTreeContainer = class
@@ -115,7 +116,7 @@ type
     procedure ParseExc(const Msg: String);
     procedure ParseExc(const Msg: String);
   protected
   protected
     function OpLevel(t: TToken): Integer;
     function OpLevel(t: TToken): Integer;
-    Function TokenToExprOp (AToken : TToken; Const AString : String) : TExprOpCode;
+    Function TokenToExprOp (AToken : TToken) : TExprOpCode;
     function CreateElement(AClass: TPTreeElement; const AName: String;
     function CreateElement(AClass: TPTreeElement; const AName: String;
       AParent: TPasElement): TPasElement;overload;
       AParent: TPasElement): TPasElement;overload;
     function CreateElement(AClass: TPTreeElement; const AName: String;
     function CreateElement(AClass: TPTreeElement; const AName: String;
@@ -123,8 +124,8 @@ type
     Function IsHint(Const S : String; var AHint : TPasMemberHint) : Boolean;
     Function IsHint(Const S : String; var AHint : TPasMemberHint) : Boolean;
     Function CheckHint(Element : TPasElement; ExpectSemiColon : Boolean) : TPasMemberHints;
     Function CheckHint(Element : TPasElement; ExpectSemiColon : Boolean) : TPasMemberHints;
 
 
-    function ParseParams(paramskind: TPasExprKind): TPasExprPart;
-    function ParseExpIdent: TPasExprPart;
+    function ParseParams(paramskind: TPasExprKind): TParamsExpr;
+    function ParseExpIdent: TPasExpr;
   public
   public
     Options : set of TPOptions;
     Options : set of TPOptions;
     CurModule: TPasModule;
     CurModule: TPasModule;
@@ -142,7 +143,7 @@ type
     function ParseComplexType(Parent : TPasElement = Nil): TPasType;
     function ParseComplexType(Parent : TPasElement = Nil): TPasType;
     procedure ParseArrayType(Element: TPasArrayType);
     procedure ParseArrayType(Element: TPasArrayType);
     procedure ParseFileType(Element: TPasFileType);
     procedure ParseFileType(Element: TPasFileType);
-    function DoParseExpression: TPasExprPart;
+    function DoParseExpression: TPasExpr;
     function ParseExpression: String;
     function ParseExpression: String;
     function ParseCommand: String; // single, not compound command like begin..end
     function ParseCommand: String; // single, not compound command like begin..end
     procedure AddProcOrFunction(Declarations: TPasDeclarations; AProc: TPasProcedure);
     procedure AddProcOrFunction(Declarations: TPasDeclarations; AProc: TPasProcedure);
@@ -646,21 +647,23 @@ const
   ];
   ];
 
 
 
 
-function TPasParser.ParseParams(paramskind: TPasExprKind): TPasExprPart;
+function TPasParser.ParseParams(paramskind: TPasExprKind): TParamsExpr;
 var
 var
-  params  : TPasExprPart;
-  p       : TPasExprPart;
+  params  : TParamsExpr;
+  p       : TPasExpr;
   PClose  : TToken;
   PClose  : TToken;
 begin
 begin
   Result:=nil;
   Result:=nil;
-  if CurToken<>tkBraceOpen then Exit;
 
 
-  if paramskind in [pekArrayParams, pekSet] then
-    PClose:=tkSquaredBraceClose
-  else
+  if paramskind in [pekArrayParams, pekSet] then begin
+    if CurToken<>tkSquaredBraceOpen then Exit;
+    PClose:=tkSquaredBraceClose;
+  end else begin
+    if CurToken<>tkBraceOpen then Exit;
     PClose:=tkBraceClose;
     PClose:=tkBraceClose;
+  end;
 
 
-  params:=TPasExprPart.Create(paramskind);
+  params:=TParamsExpr.Create(paramskind);
   try
   try
     NextToken;
     NextToken;
     if not (CurToken in EndExprToken) then begin
     if not (CurToken in EndExprToken) then begin
@@ -689,7 +692,7 @@ begin
   end;
   end;
 end;
 end;
 
 
-Function TPasParser.TokenToExprOp (AToken : TToken; Const AString : String) : TExprOpCode;
+Function TPasParser.TokenToExprOp (AToken : TToken) : TExprOpCode;
 
 
 begin
 begin
   Case AToken of
   Case AToken of
@@ -718,68 +721,65 @@ begin
     tkNot                   : Result:=eopNot;
     tkNot                   : Result:=eopNot;
     tkIn                    : Result:=eopIn;
     tkIn                    : Result:=eopIn;
   else
   else
-    Raise Exception.CreateFmt('Not an operand: (%d : %s)',[AToken,Astring]);   
+    Raise Exception.CreateFmt('Not an operand: (%d : %s)',[AToken,TokenInfos[AToken]]);
   end;
   end;
 end;
 end;
  
  
-function TPasParser.ParseExpIdent:TPasExprPart;
+function TPasParser.ParseExpIdent:TPasExpr;
 var
 var
-  x, t    : TPasExprPart;
-  eofid   : Boolean;
+  x       : TPasExpr;
+  prm     : TParamsExpr;
+  u       : TUnaryExpr;
+  b       : TBinaryExpr;
 begin
 begin
   Result:=nil;
   Result:=nil;
-  eofid:=True;
   case CurToken of
   case CurToken of
-    tkString: begin
-      x:=TPasExprPart.CreateWithText(pekString, CurTokenString);
-      NextToken;
-    end;
-    tkNumber:
-    begin
-      x:=TPasExprPart.CreateWithText(pekNumber, CurTokenString);
-      NextToken;
-    end;
-    tkSquaredBraceOpen:
-      x:=ParseParams(pekSet);
-    tkIdentifier: begin
-      x:=TPasExprPart.CreateWithText(pekIdent, CurTokenText);
-      eofid:=False;
-    end;
+    tkString:           x:=TPrimitiveExpr.Create(pekString, CurTokenString);
+    tkNumber:           x:=TPrimitiveExpr.Create(pekNumber, CurTokenString);
+    tkIdentifier:       x:=TPrimitiveExpr.Create(pekIdent, CurTokenText);
+    tkSquaredBraceOpen: x:=ParseParams(pekSet);
+  else
+    ParseExc(SParserExpectedIdentifier);
   end;
   end;
 
 
-  if eofid then begin
-    Result:=x;
-    Exit;
-  end;
+  if x.Kind<>pekSet then NextToken;
 
 
   try
   try
-    NextToken;
-    while CurToken in [tkBraceOpen, tkSquaredBraceOpen, tkCaret] do
-      case CurToken of
-        tkBraceOpen: begin
-          t:=ParseParams(pekFuncParams);
-          if not Assigned(t) then Exit;
-          t.left:=x;
-          x:=t;
-        end;
-        tkSquaredBraceOpen: begin
-          t:=ParseParams(pekArrayParams);
-          if not Assigned(t) then Exit;
-          t.left:=x;
-          x:=t;
-        end;
-        tkCaret: begin
-          t:=TPasExprPart.CreatePostfix(x, TokenToExprOp(CurToken,TokenInfos[CurToken]));
-          NextToken;
-          x:=t;
+    if x.Kind=pekIdent then begin
+      while CurToken in [tkBraceOpen, tkSquaredBraceOpen, tkCaret] do
+        case CurToken of
+          tkBraceOpen: begin
+            prm:=ParseParams(pekFuncParams);
+            if not Assigned(prm) then Exit;
+            prm.Value:=x;
+            x:=prm;
+          end;
+          tkSquaredBraceOpen: begin
+            prm:=ParseParams(pekArrayParams);
+            if not Assigned(prm) then Exit;
+            prm.Value:=x;
+            x:=prm;
+          end;
+          tkCaret: begin
+            u:=TUnaryExpr.Create(x, TokenToExprOp(CurToken));
+            x:=u;
+            NextToken;
+          end;
         end;
         end;
+
+      if CurToken in [tkDot, tkas] then begin
+        NextToken;
+        b:=TBinaryExpr.Create(x, ParseExpIdent, TokenToExprOp(CurToken));
+        if not Assigned(b.right) then Exit; // error
+        x:=b;
       end;
       end;
+    end;
 
 
-    if CurToken in [tkDot, tkas] then begin
+    if CurToken = tkDotDot then begin
       NextToken;
       NextToken;
-      x:=TPasExprPart.CreateBinary(x, ParseExpIdent, TokenToExprOp(CurToken,TokenInfos[CurToken]));
-      if not Assigned(x.right) then
-        Exit; // error?
+      b:=TBinaryExpr.CreateRange(x, DoParseExpression);
+      if not Assigned(b.right) then Exit; // error
+      x:=b;
     end;
     end;
 
 
     Result:=x;
     Result:=x;
@@ -804,22 +804,23 @@ begin
   end;
   end;
 end;
 end;
 
 
-function TPasParser.DoParseExpression: TPasExprPart;
+function TPasParser.DoParseExpression: TPasExpr;
 var
 var
   expstack  : TList;
   expstack  : TList;
   opstack   : TList;
   opstack   : TList;
   pcount    : Integer;
   pcount    : Integer;
-  x         : TPasExprPart;
+  x         : TPasExpr;
   i         : Integer;
   i         : Integer;
   tempop    : TToken;
   tempop    : TToken;
+  AllowEnd  : Boolean;
   
   
 const
 const
   PrefixSym = [tkPlus, tkMinus, tknot, tkAt]; // + - not @
   PrefixSym = [tkPlus, tkMinus, tknot, tkAt]; // + - not @
 
 
-  function PopExp: TPasExprPart; inline;
+  function PopExp: TPasExpr; inline;
   begin
   begin
     if expstack.Count>0 then begin
     if expstack.Count>0 then begin
-      Result:=TPasExprPart(expstack[expstack.Count-1]);
+      Result:=TPasExpr(expstack[expstack.Count-1]);
       expstack.Delete(expstack.Count-1);
       expstack.Delete(expstack.Count-1);
     end else
     end else
       Result:=nil;
       Result:=nil;
@@ -845,13 +846,13 @@ const
   procedure PopAndPushOperator;
   procedure PopAndPushOperator;
   var
   var
     t       : TToken;
     t       : TToken;
-    xright  : TPasExprPart;
-    xleft   : TPasExprPart;
+    xright  : TPasExpr;
+    xleft   : TPasExpr;
   begin
   begin
     t:=PopOper;
     t:=PopOper;
     xright:=PopExp;
     xright:=PopExp;
     xleft:=PopExp;
     xleft:=PopExp;
-    expstack.Add(TPasExprPart.CreateBinary(xleft, xright, TokenToExprOp(t,TokenInfos[t])));
+    expstack.Add(TBinaryExpr.Create(xleft, xright, TokenToExprOp(t)));
   end;
   end;
 
 
 begin
 begin
@@ -860,6 +861,7 @@ begin
   opstack := TList.Create;
   opstack := TList.Create;
   try
   try
     repeat
     repeat
+      AllowEnd:=True;
       pcount:=0;
       pcount:=0;
       while CurToken in PrefixSym do begin
       while CurToken in PrefixSym do begin
         PushOper(CurToken);
         PushOper(CurToken);
@@ -872,18 +874,20 @@ begin
         x:=DoParseExpression();
         x:=DoParseExpression();
         if CurToken<>tkBraceClose then Exit;
         if CurToken<>tkBraceClose then Exit;
         NextToken;
         NextToken;
-      end else
+      end else begin
         x:=ParseExpIdent;
         x:=ParseExpIdent;
+      end;
 
 
       if not Assigned(x) then Exit;
       if not Assigned(x) then Exit;
       expstack.Add(x);
       expstack.Add(x);
       for i:=1 to pcount do
       for i:=1 to pcount do
         begin
         begin
         tempop:=PopOper;
         tempop:=PopOper;
-        expstack.Add( TPasExprPart.CreatePrefix( PopExp, TokenToExprOp(tempop,TokenInfos[tempop]) ));
+        expstack.Add( TUnaryExpr.Create( PopExp, TokenToExprOp(tempop) ));
         end;
         end;
       if not (CurToken in EndExprToken) then begin
       if not (CurToken in EndExprToken) then begin
         // Adjusting order of the operations
         // Adjusting order of the operations
+        AllowEnd:=False;
         tempop:=PeekOper;
         tempop:=PeekOper;
         while (opstack.Count>0) and (OpLevel(tempop)>=OpLevel(CurToken)) do begin
         while (opstack.Count>0) and (OpLevel(tempop)>=OpLevel(CurToken)) do begin
           PopAndPushOperator;
           PopAndPushOperator;
@@ -893,12 +897,12 @@ begin
         NextToken;
         NextToken;
       end;
       end;
 
 
-    until CurToken in EndExprToken;
+    until AllowEnd and (CurToken in EndExprToken);
 
 
     while opstack.Count>0 do PopAndPushOperator;
     while opstack.Count>0 do PopAndPushOperator;
 
 
     // only 1 expression should be on the stack, at the end of the correct expression
     // only 1 expression should be on the stack, at the end of the correct expression
-    if expstack.Count=1 then Result:=TPasExprPart(expstack[0]);
+    if expstack.Count=1 then Result:=TPasExpr(expstack[0]);
 
 
   finally
   finally
     if not Assigned(Result) then begin
     if not Assigned(Result) then begin
@@ -995,7 +999,7 @@ begin
     if CurToken=tkString then
     if CurToken=tkString then
       begin
       begin
       If (Length(CurTokenText)>0) and (CurTokenText[1]=#0) then
       If (Length(CurTokenText)>0) and (CurTokenText[1]=#0) then
-        Writeln('First char is null : "',CurTokenText,'"');
+        Raise Exception.Create('First char is null : "'+CurTokenText+'"');
       Result := Result + ''''+StringReplace(CurTokenText,'''','''''',[rfReplaceAll])+''''
       Result := Result + ''''+StringReplace(CurTokenText,'''','''''',[rfReplaceAll])+''''
       end
       end
     else
     else

+ 0 - 1
packages/fcl-passrc/src/pscanner.pp

@@ -566,7 +566,6 @@ end;
 
 
 procedure TPascalScanner.Error(const Msg: string; Args: array of Const);
 procedure TPascalScanner.Error(const Msg: string; Args: array of Const);
 begin
 begin
-  writeln('TPascalScanner.Error ',FileResolver.FIncludePaths.Text);
   raise EScannerError.CreateFmt(Msg, Args);
   raise EScannerError.CreateFmt(Msg, Args);
 end;
 end;