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/htmlindexer.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/paslznonslide.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/unblockchm.pp -text svneol=native#test/plain
 packages/dbus/Makefile svneol=native#text/plain
 packages/dbus/Makefile.fpc 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
 endif
 ifeq ($(FULL_TARGET),i386-win32)
-override TARGET_PROGRAMS+=chmcmd chmls  unblockchm
+override TARGET_PROGRAMS+=chmcmd chmls
 endif
 ifeq ($(FULL_TARGET),i386-os2)
 override TARGET_PROGRAMS+=chmcmd chmls
@@ -396,7 +396,7 @@ ifeq ($(FULL_TARGET),x86_64-darwin)
 override TARGET_PROGRAMS+=chmcmd chmls
 endif
 ifeq ($(FULL_TARGET),x86_64-win64)
-override TARGET_PROGRAMS+=chmcmd chmls  unblockchm
+override TARGET_PROGRAMS+=chmcmd chmls
 endif
 ifeq ($(FULL_TARGET),x86_64-embedded)
 override TARGET_PROGRAMS+=chmcmd chmls
@@ -447,184 +447,187 @@ ifeq ($(FULL_TARGET),mipsel-linux)
 override TARGET_PROGRAMS+=chmcmd chmls
 endif
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 override INSTALL_FPCPACKAGE=y
 ifeq ($(FULL_TARGET),i386-linux)
@@ -2864,4 +2867,3 @@ endif
 .NOTPARALLEL:
 cdmcmd$(EXEEXT): chmcmd.lpr
 chmls$(EXEEXT): chmls.lpr
-unblockchm$(EXEEXT): unblockchm.pp

+ 2 - 4
packages/chm/Makefile.fpc

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

+ 16 - 0
packages/chm/fpmake.pp

@@ -93,6 +93,22 @@ begin
         begin
           AddUnit('htmlindexer');
         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');
     T:=P.Targets.AddProgram('chmls.lpr');

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

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

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

@@ -218,7 +218,7 @@ Const
        'COMPRESS','COPYRIGHT','COMPATIBILITY','COMPILED FILE','CONTENTS FILE',
        'CREATE CHI FILE','DBCS','DEFAULT FONT','DEFAULT WINDOW','DEFAULT TOPIC',
        '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');
 
 
@@ -524,6 +524,9 @@ var
   nd        : TChmContextNode;
 
 begin
+ { Defaults other than global }
+   MakeBinaryIndex:=True;
+
   Fini:=TMeminiFile.Create(AFileName);
   secs := TStringList.create;
   strs := TStringList.create;

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

@@ -32,19 +32,27 @@ uses
 
 type
 
-  { TJunkObject }
+  { TListObject }
 
-  TJunkObject = class
+  TListObject = class
     Section  : Integer;
     count    : integer;
     donotpage: boolean;
     procedure OnFileEntry(Name: String; Offset, UncompressedSize, ASection: Integer);
   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
-  CmdNames : array [TCmdEnum] of String = ('LIST','EXTRACT','');
+  CmdNames : array [TCmdEnum] of String = ('LIST','EXTRACT','EXTRACTALL','UNBLOCK','');
 
 var
   theopts : array[1..2] of TOption;
@@ -60,14 +68,28 @@ begin
   writeln(stderr,' -n          : do not page list output');
   writeln(stderr);
   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,' 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,'            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);
 end;
 
+procedure WrongNrParam(cmd:string;number:integer);
+
+begin
+  writeln(stderr,' Wrong number of parameters for ',cmd,' ',number);
+  usage;
+  halt(1);
+end;
+
 procedure InitOptions;
 begin
   with theopts[1] do
@@ -98,9 +120,34 @@ procedure WriteStrAdj(Str: String; CharWidth: Integer);
     Write(OutString + Str); // to stdout
   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);
 begin
   Inc(Count);
@@ -117,13 +164,64 @@ begin
   WriteLn(Name);
 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;
 
 procedure ListChm(Const Name:string;Section:Integer);
 var
   ITS: TITSFReader;
   Stream: TFileStream;
-  JunkObject: TJunkObject;
+  JunkObject: TListObject;
 
 begin
   if not Fileexists(name) then
@@ -133,7 +231,7 @@ begin
     end;
 
   Stream := TFileStream.Create(name, fmOpenRead);
-  JunkObject := TJunkObject.Create;
+  JunkObject := TListObject.Create;
   JunkObject.Section:=Section;
   JunkObject.Count:=0;
   JunkObject.DoNotPage:=DoNotPage;
@@ -181,6 +279,94 @@ begin
     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);
 
 var s           : ansistring;
@@ -261,11 +447,7 @@ begin
                           ListChm(localparams[0],Section);
                         end;
                   else
-                    begin
-                      writeln(stderr,' Wrong number of parameters for LIST ',length(localparams));
-                      usage;
-                      halt(1);
-                    end
+                    WrongNrParam(cmdnames[cmd],length(localparams));
                    end; {case}
                 end; { cmdlist}
       cmdextract : begin
@@ -273,13 +455,23 @@ begin
                       2: ExtractFile(localparams[0],localparams[1],extractfilename(localparams[1]));
                       3: ExtractFile(localparams[0],localparams[1],localparams[2]);
                      else
-                      begin
-                        writeln(stderr,' Wrong number of parameters for LIST ',length(localparams));
-                        usage;
-                        halt(1);
-                      end
+                       WrongNrParam(cmdnames[cmd],length(localparams));
                      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
  else

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

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

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

@@ -137,6 +137,7 @@ Type
     FDefaultFont: String;
     FDefaultPage: String;
     FFullTextSearch: Boolean;
+    FFullTextSearchAvailable: Boolean;
     FSearchTitlesOnly: Boolean;
     FStringsStream: TMemoryStream; // the #STRINGS file
     FTopicsStream: TMemoryStream;  // the #TOPICS file
@@ -248,7 +249,7 @@ begin
     ITSFsig := ITSFFileSig;
     Version := NToLE(DWord(3));
     // 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));
     TimeStamp:= NToBE(MilliSecondOfTheDay(Now)); //bigendian
     LanguageID := NToLE(DWord($0409)); // English / English_US
@@ -970,7 +971,7 @@ begin
 
   FSection0.WriteDWord(NToLE(DWord($0409)));
   FSection0.WriteDWord(1);
-  FSection0.WriteDWord(NToLE(DWord(Ord(FFullTextSearch))));
+  FSection0.WriteDWord(NToLE(DWord(Ord(FFullTextSearch and FFullTextSearchAvailable))));
   FSection0.WriteDWord(0);
   FSection0.WriteDWord(0);
 
@@ -1256,6 +1257,14 @@ begin
   if FTopicsStream.Size = 0 then
     Exit;
   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.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';
 
 type
-  TPasExprKind = (pekIdent, pekNumber, pekString, pekSet,
-     pekPrefix, pekPostfix, pekBinary, pekFuncParams, pekArrayParams);
+  TPasExprKind = (pekIdent, pekNumber, pekString, pekSet, pekRange,
+     pekUnary, pekBinary, pekFuncParams, pekArrayParams);
 
   TExprOpCode = (eopNone,
                  eopAdd,eopSubtract,eopMultiply,eopDivide, eopDiv,eopMod, eopPower,// arithmetic
@@ -79,24 +79,45 @@ type
                  eopIn,eopIs,eopAs, eopSymmetricaldifference, // Specials
                  eopAddress);
   
-  { TPasExprPart }
+  { TPasExpr }
 
-  TPasExprPart = class 
+  TPasExpr = class
     Kind      : TPasExprKind;
-    Left      : TPasExprPart;
-    Right     : TPasExprPart;
     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;
-    procedure AddParam(xp: TPasExprPart);
   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.
   TPassTreeVisitor = class;
@@ -467,7 +488,7 @@ type
     Value: string;
     Modifiers : string;
     AbsoluteLocation : String;
-    Expr: TPasExprPart;
+    Expr: TPasExpr;
   end;
 
   { TPasConst }
@@ -2315,52 +2336,61 @@ begin
   Result:=true;
 end;
 
-{ TPasExprPart }
+{ TPasExpr }
 
-constructor TPasExprPart.Create(AKind:TPasExprKind);
+constructor TPasExpr.Create(AKind: TPasExprKind; AOpCode: TexprOpcode);
 begin
   Kind:=AKind;
+  OpCode:=AOpCode;
 end;
 
-constructor TPasExprPart.CreateWithText(AKind:TPasExprKind;const AValue: AnsiString);
+{ TPrimitiveExpr }
+
+constructor TPrimitiveExpr.Create(AKind: TPasExprKind; const AValue : Ansistring);
 begin
-  Create(AKind);
+  inherited Create(AKind, eopNone);
   Value:=AValue;
 end;
 
-constructor TPasExprPart.CreatePrefix(rightExp: TPasExprPart; const AOpCode: TExprOpCode);
+{ TUnaryExpr }
+
+constructor TUnaryExpr.Create(AOperand: TPasExpr; AOpCode: TExprOpCode);
 begin
-  Create(pekPrefix);
-  right:=rightExp;
-  Opcode:=AOpCode;
+  inherited Create(pekUnary, AOpCode);
+  Operand:=AOperand;
 end;
 
-constructor TPasExprPart.CreatePostfix(leftExp: TPasExprPart; const AOpCode: TExprOpCode);
+destructor TUnaryExpr.Destroy;
 begin
-  Create(pekPostfix);
-  left:=leftExp;
-  Opcode:=AOpCode;
+  Operand.Free;
 end;
 
-constructor TPasExprPart.CreateBinary(xleft, xright: TPasExprPart; const AOpCode: TExprOpcode);
+{ TBinaryExpr }
+
+constructor TBinaryExpr.Create(xleft,xright:TPasExpr; AOpCode:TExprOpCode);
 begin
-  Create(pekBinary);
+  inherited Create(pekBinary, AOpCode);
   left:=xleft;
   right:=xright;
-  Opcode:=AOpCode;
 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
   left.Free;
   right.Free;
-  for i:=0 to length(Params)-1 do Params[i].Free;
   inherited Destroy;
 end;
 
-procedure TPasExprPart.AddParam(xp:TPasExprPart);
+{ TParamsExpr }
+
+procedure TParamsExpr.AddParam(xp:TPasExpr);
 var
   i : Integer;
 begin
@@ -2369,6 +2399,17 @@ begin
   Params[i]:=xp;
 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.

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

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

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

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