瀏覽代碼

Merged revisions 9693-10480 via svnmerge from
svn+ssh://svn.freepascal.org/FPC/svn/fpc/branches/resources

........
r9694 | michael | 2008-01-09 21:31:18 +0100 (Wed, 09 Jan 2008) | 1 line

* Initial check-in
........
r9695 | michael | 2008-01-09 21:35:58 +0100 (Wed, 09 Jan 2008) | 1 line

* New version from Giulio Bernardi
........
r9697 | michael | 2008-01-09 21:41:54 +0100 (Wed, 09 Jan 2008) | 1 line

* Patch from Giulio Bernardi with resource support
........
r9698 | michael | 2008-01-09 21:46:33 +0100 (Wed, 09 Jan 2008) | 1 line

* Patch from Giulio Bernardi to add more resource testing
........
r9699 | michael | 2008-01-09 21:57:26 +0100 (Wed, 09 Jan 2008) | 1 line

* New tool from Giulio Bernardi
........
r9700 | michael | 2008-01-09 21:58:23 +0100 (Wed, 09 Jan 2008) | 1 line

* New tool from Giulio Bernardi
........
r9701 | michael | 2008-01-09 22:01:54 +0100 (Wed, 09 Jan 2008) | 1 line

* Added fcl-res
........
r9702 | michael | 2008-01-09 22:01:58 +0100 (Wed, 09 Jan 2008) | 1 line

* Added fcl-res
........
r9703 | michael | 2008-01-10 08:54:26 +0100 (Thu, 10 Jan 2008) | 1 line

* Fixed double code
........
r9704 | jonas | 2008-01-10 10:59:20 +0100 (Thu, 10 Jan 2008) | 2 lines

- removed duplicate code
........
r9705 | jonas | 2008-01-10 11:25:21 +0100 (Thu, 10 Jan 2008) | 2 lines

+ added missing fcl-res dependencies
........
r9706 | jonas | 2008-01-10 11:58:30 +0100 (Thu, 10 Jan 2008) | 2 lines

+ dependencies for fpintres and fpextres
........
r9707 | yury | 2008-01-10 12:47:51 +0100 (Thu, 10 Jan 2008) | 3 lines

* Fixed compilation of resource, which is included in a unit located in different folder than main source.
* .res files must be copied to units output folder, otherwise .res files will not be found when only compiled units path is available and compiler does not know anything about sources folder.
* Improved resource related error messages.
........
r9708 | michael | 2008-01-10 12:52:13 +0100 (Thu, 10 Jan 2008) | 1 line

* Removed double source after end.
........
r9709 | michael | 2008-01-10 12:52:48 +0100 (Thu, 10 Jan 2008) | 1 line

* No longer needed
........
r9710 | tom_at_work | 2008-01-10 22:09:08 +0100 (Thu, 10 Jan 2008) | 1 line

* properly align FPC_RESLOCATION so that linking does not fail on some architectures (e.g. ppc64)
........
r9711 | tom_at_work | 2008-01-10 23:53:12 +0100 (Thu, 10 Jan 2008) | 1 line

* fix splitting of 64 bit load/stores from/to unaligned memory locations into multiple load/stores, which in some cases generated wrong code
........
r9712 | michael | 2008-01-11 11:00:08 +0100 (Fri, 11 Jan 2008) | 1 line

* Fixed bug in BSS section on 64-bit platforms
........
r9720 | giulio | 2008-01-12 10:02:04 +0100 (Sat, 12 Jan 2008) | 1 line

Updated fcl-res documentation: occurrences of reslib changed to fcl-res.
........
r9740 | giulio | 2008-01-13 19:36:44 +0100 (Sun, 13 Jan 2008) | 3 lines

- Don't try to compile resources on systems with a non windows-like resource support.
- Don't add the .or file to the list of object files if resource compiling failed.
........
r10201 | giulio | 2008-02-04 11:35:44 +0100 (Mon, 04 Feb 2008) | 5 lines

* resource compiling supported on OS/2 via wrc
* CompileResourceFiles and CollectResourceFiles don't do target-specific checks anymore
* refactored a bit
........
r10389 | giulio | 2008-02-25 21:32:52 +0100 (Mon, 25 Feb 2008) | 2 lines

Deleted test file which was committed by mistake
........
r10472 | giulio | 2008-03-10 12:22:18 +0100 (Mon, 10 Mar 2008) | 2 lines

changed define FPC_HAS_RESOURCES to FPC_HAS_WINLIKERESOURCES
........

git-svn-id: trunk@10481 -

michael 17 年之前
父節點
當前提交
174de3eab1
共有 100 個文件被更改,包括 23097 次插入755 次删除
  1. 101 6
      .gitattributes
  2. 223 226
      compiler/comprsrc.pas
  3. 1 0
      compiler/fmodule.pas
  4. 24 5
      compiler/msg/errore.msg
  5. 7 2
      compiler/msgidx.inc
  6. 97 84
      compiler/msgtxt.inc
  7. 32 3
      compiler/options.pas
  8. 9 0
      compiler/parser.pas
  9. 106 32
      compiler/pmodules.pas
  10. 27 0
      compiler/powerpc64/cgcpu.pas
  11. 59 0
      compiler/rescmn.pas
  12. 1 1
      compiler/scandir.pas
  13. 17 13
      compiler/systems.pas
  14. 43 22
      compiler/systems/i_bsd.pas
  15. 9 6
      compiler/systems/i_emx.pas
  16. 21 43
      compiler/systems/i_linux.pas
  17. 9 6
      compiler/systems/i_os2.pas
  18. 5 5
      compiler/systems/i_sunos.pas
  19. 8 6
      compiler/systems/i_win.pas
  20. 4 1
      compiler/systems/t_bsd.pas
  21. 1 1
      compiler/systems/t_emx.pas
  22. 3 24
      compiler/systems/t_linux.pas
  23. 1 1
      compiler/systems/t_os2.pas
  24. 4 2
      compiler/systems/t_sunos.pas
  25. 10 47
      compiler/systems/t_win.pas
  26. 155 213
      packages/Makefile
  27. 6 6
      packages/Makefile.fpc
  28. 2408 0
      packages/fcl-res/Makefile
  29. 31 0
      packages/fcl-res/Makefile.fpc
  30. 240 0
      packages/fcl-res/src/acceleratorsresource.pp
  31. 261 0
      packages/fcl-res/src/bitmapresource.pp
  32. 164 0
      packages/fcl-res/src/coffconsts.pp
  33. 308 0
      packages/fcl-res/src/coffreader.pp
  34. 87 0
      packages/fcl-res/src/cofftypes.pp
  35. 637 0
      packages/fcl-res/src/coffwriter.pp
  36. 238 0
      packages/fcl-res/src/dfmreader.pp
  37. 144 0
      packages/fcl-res/src/elfconsts.pp
  38. 67 0
      packages/fcl-res/src/elfdefaulttarget.inc
  39. 316 0
      packages/fcl-res/src/elfreader.pp
  40. 282 0
      packages/fcl-res/src/elfsubreader.inc
  41. 446 0
      packages/fcl-res/src/elfsubwriter.inc
  42. 142 0
      packages/fcl-res/src/elftypes.pp
  43. 620 0
      packages/fcl-res/src/elfwriter.pp
  44. 231 0
      packages/fcl-res/src/externalreader.pp
  45. 56 0
      packages/fcl-res/src/externaltypes.pp
  46. 297 0
      packages/fcl-res/src/externalwriter.pp
  47. 53 0
      packages/fcl-res/src/fpcrestypes.pp
  48. 314 0
      packages/fcl-res/src/groupcursorresource.pp
  49. 284 0
      packages/fcl-res/src/groupiconresource.pp
  50. 268 0
      packages/fcl-res/src/groupresource.pp
  51. 65 0
      packages/fcl-res/src/icocurtypes.pp
  52. 203 0
      packages/fcl-res/src/machoconsts.pp
  53. 45 0
      packages/fcl-res/src/machodefaulttarget.inc
  54. 290 0
      packages/fcl-res/src/machoreader.pp
  55. 160 0
      packages/fcl-res/src/machosubreader.inc
  56. 354 0
      packages/fcl-res/src/machosubwriter.inc
  57. 151 0
      packages/fcl-res/src/machotypes.pp
  58. 618 0
      packages/fcl-res/src/machowriter.pp
  59. 332 0
      packages/fcl-res/src/prova.pp
  60. 348 0
      packages/fcl-res/src/resdatastream.pp
  61. 151 0
      packages/fcl-res/src/resfactory.pp
  62. 62 0
      packages/fcl-res/src/resmerger.pp
  63. 1155 0
      packages/fcl-res/src/resource.pp
  64. 560 0
      packages/fcl-res/src/resourcetree.pp
  65. 260 0
      packages/fcl-res/src/resreader.pp
  66. 199 0
      packages/fcl-res/src/reswriter.pp
  67. 259 0
      packages/fcl-res/src/stringtableresource.pp
  68. 185 0
      packages/fcl-res/src/strtable.pp
  69. 75 0
      packages/fcl-res/src/versionconsts.pp
  70. 592 0
      packages/fcl-res/src/versionresource.pp
  71. 377 0
      packages/fcl-res/src/versiontypes.pp
  72. 126 0
      packages/fcl-res/src/winpeimagereader.pp
  73. 228 0
      packages/fcl-res/xml/acceleratorsresource.xml
  74. 120 0
      packages/fcl-res/xml/bitmapresource.xml
  75. 32 0
      packages/fcl-res/xml/clean.sh
  76. 70 0
      packages/fcl-res/xml/coffreader.xml
  77. 49 0
      packages/fcl-res/xml/cofftypes.xml
  78. 99 0
      packages/fcl-res/xml/coffwriter.xml
  79. 43 0
      packages/fcl-res/xml/dfmreader.xml
  80. 807 0
      packages/fcl-res/xml/elfconsts.xml
  81. 111 0
      packages/fcl-res/xml/elfreader.xml
  82. 106 0
      packages/fcl-res/xml/elfwriter.xml
  83. 73 0
      packages/fcl-res/xml/externalreader.xml
  84. 311 0
      packages/fcl-res/xml/externaltypes.xml
  85. 97 0
      packages/fcl-res/xml/externalwriter.xml
  86. 134 0
      packages/fcl-res/xml/fpdoc.css
  87. 71 0
      packages/fcl-res/xml/groupcursorresource.xml
  88. 71 0
      packages/fcl-res/xml/groupiconresource.xml
  89. 144 0
      packages/fcl-res/xml/groupresource.xml
  90. 66 0
      packages/fcl-res/xml/machoreader.xml
  91. 945 0
      packages/fcl-res/xml/machotypes.xml
  92. 77 0
      packages/fcl-res/xml/machowriter.xml
  93. 33 0
      packages/fcl-res/xml/makehtml.sh
  94. 260 0
      packages/fcl-res/xml/resdatastream.xml
  95. 122 0
      packages/fcl-res/xml/resfactory.xml
  96. 2843 0
      packages/fcl-res/xml/resource.xml
  97. 480 0
      packages/fcl-res/xml/resourcetree.xml
  98. 46 0
      packages/fcl-res/xml/resreader.xml
  99. 46 0
      packages/fcl-res/xml/reswriter.xml
  100. 169 0
      packages/fcl-res/xml/stringtableresource.xml

+ 101 - 6
.gitattributes

@@ -430,6 +430,7 @@ compiler/rabase.pas svneol=native#text/plain
 compiler/rasm.pas svneol=native#text/plain
 compiler/rautils.pas svneol=native#text/plain
 compiler/regvars.pas svneol=native#text/plain
+compiler/rescmn.pas svneol=native#text/plain
 compiler/rgbase.pas svneol=native#text/plain
 compiler/rgobj.pas svneol=native#text/plain
 compiler/scandir.pas svneol=native#text/plain
@@ -1513,6 +1514,83 @@ packages/fcl-registry/tests/Makefile svneol=native#text/plain
 packages/fcl-registry/tests/Makefile.fpc -text
 packages/fcl-registry/tests/regtestframework.pp -text
 packages/fcl-registry/tests/testbasics.pp svneol=native#text/plain
+packages/fcl-res/Makefile svneol=native#text/plain
+packages/fcl-res/Makefile.fpc svneol=native#text/plain
+packages/fcl-res/src/acceleratorsresource.pp svneol=native#text/plain
+packages/fcl-res/src/bitmapresource.pp svneol=native#text/plain
+packages/fcl-res/src/coffconsts.pp svneol=native#text/plain
+packages/fcl-res/src/coffreader.pp svneol=native#text/plain
+packages/fcl-res/src/cofftypes.pp svneol=native#text/plain
+packages/fcl-res/src/coffwriter.pp svneol=native#text/plain
+packages/fcl-res/src/dfmreader.pp svneol=native#text/plain
+packages/fcl-res/src/elfconsts.pp svneol=native#text/plain
+packages/fcl-res/src/elfdefaulttarget.inc svneol=native#text/plain
+packages/fcl-res/src/elfreader.pp svneol=native#text/plain
+packages/fcl-res/src/elfsubreader.inc svneol=native#text/plain
+packages/fcl-res/src/elfsubwriter.inc svneol=native#text/plain
+packages/fcl-res/src/elftypes.pp svneol=native#text/plain
+packages/fcl-res/src/elfwriter.pp svneol=native#text/plain
+packages/fcl-res/src/externalreader.pp svneol=native#text/plain
+packages/fcl-res/src/externaltypes.pp svneol=native#text/plain
+packages/fcl-res/src/externalwriter.pp svneol=native#text/plain
+packages/fcl-res/src/fpcrestypes.pp svneol=native#text/plain
+packages/fcl-res/src/groupcursorresource.pp svneol=native#text/plain
+packages/fcl-res/src/groupiconresource.pp svneol=native#text/plain
+packages/fcl-res/src/groupresource.pp svneol=native#text/plain
+packages/fcl-res/src/icocurtypes.pp svneol=native#text/plain
+packages/fcl-res/src/machoconsts.pp svneol=native#text/plain
+packages/fcl-res/src/machodefaulttarget.inc svneol=native#text/plain
+packages/fcl-res/src/machoreader.pp svneol=native#text/plain
+packages/fcl-res/src/machosubreader.inc svneol=native#text/plain
+packages/fcl-res/src/machosubwriter.inc svneol=native#text/plain
+packages/fcl-res/src/machotypes.pp svneol=native#text/plain
+packages/fcl-res/src/machowriter.pp svneol=native#text/plain
+packages/fcl-res/src/prova.pp svneol=native#text/plain
+packages/fcl-res/src/resdatastream.pp svneol=native#text/plain
+packages/fcl-res/src/resfactory.pp svneol=native#text/plain
+packages/fcl-res/src/resmerger.pp svneol=native#text/plain
+packages/fcl-res/src/resource.pp svneol=native#text/plain
+packages/fcl-res/src/resourcetree.pp svneol=native#text/plain
+packages/fcl-res/src/resreader.pp svneol=native#text/plain
+packages/fcl-res/src/reswriter.pp svneol=native#text/plain
+packages/fcl-res/src/stringtableresource.pp svneol=native#text/plain
+packages/fcl-res/src/strtable.pp svneol=native#text/plain
+packages/fcl-res/src/versionconsts.pp svneol=native#text/plain
+packages/fcl-res/src/versionresource.pp svneol=native#text/plain
+packages/fcl-res/src/versiontypes.pp svneol=native#text/plain
+packages/fcl-res/src/winpeimagereader.pp svneol=native#text/plain
+packages/fcl-res/xml/acceleratorsresource.xml svneol=native#text/plain
+packages/fcl-res/xml/bitmapresource.xml svneol=native#text/plain
+packages/fcl-res/xml/clean.sh svneol=native#text/plain
+packages/fcl-res/xml/coffreader.xml svneol=native#text/plain
+packages/fcl-res/xml/cofftypes.xml svneol=native#text/plain
+packages/fcl-res/xml/coffwriter.xml svneol=native#text/plain
+packages/fcl-res/xml/dfmreader.xml svneol=native#text/plain
+packages/fcl-res/xml/elfconsts.xml svneol=native#text/plain
+packages/fcl-res/xml/elfreader.xml svneol=native#text/plain
+packages/fcl-res/xml/elfwriter.xml svneol=native#text/plain
+packages/fcl-res/xml/externalreader.xml svneol=native#text/plain
+packages/fcl-res/xml/externaltypes.xml svneol=native#text/plain
+packages/fcl-res/xml/externalwriter.xml svneol=native#text/plain
+packages/fcl-res/xml/fpdoc.css svneol=native#text/plain
+packages/fcl-res/xml/groupcursorresource.xml svneol=native#text/plain
+packages/fcl-res/xml/groupiconresource.xml svneol=native#text/plain
+packages/fcl-res/xml/groupresource.xml svneol=native#text/plain
+packages/fcl-res/xml/machoreader.xml svneol=native#text/plain
+packages/fcl-res/xml/machotypes.xml svneol=native#text/plain
+packages/fcl-res/xml/machowriter.xml svneol=native#text/plain
+packages/fcl-res/xml/makehtml.sh svneol=native#text/plain
+packages/fcl-res/xml/resdatastream.xml svneol=native#text/plain
+packages/fcl-res/xml/resfactory.xml svneol=native#text/plain
+packages/fcl-res/xml/resource.xml svneol=native#text/plain
+packages/fcl-res/xml/resourcetree.xml svneol=native#text/plain
+packages/fcl-res/xml/resreader.xml svneol=native#text/plain
+packages/fcl-res/xml/reswriter.xml svneol=native#text/plain
+packages/fcl-res/xml/stringtableresource.xml svneol=native#text/plain
+packages/fcl-res/xml/versionconsts.xml svneol=native#text/plain
+packages/fcl-res/xml/versionresource.xml svneol=native#text/plain
+packages/fcl-res/xml/versiontypes.xml svneol=native#text/plain
+packages/fcl-res/xml/winpeimagereader.xml svneol=native#text/plain
 packages/fcl-web/Makefile svneol=native#text/plain
 packages/fcl-web/Makefile.fpc svneol=native#text/plain
 packages/fcl-web/fpmake.pp svneol=native#text/plain
@@ -4806,6 +4884,7 @@ rtl/darwin/Makefile.fpc svneol=native#text/plain
 rtl/darwin/console.pp svneol=native#text/plain
 rtl/darwin/errno.inc svneol=native#text/plain
 rtl/darwin/errnostr.inc -text
+rtl/darwin/extres_multiarch.inc svneol=native#text/plain
 rtl/darwin/i386/sig_cpu.inc svneol=native#text/plain
 rtl/darwin/i386/sighnd.inc svneol=native#text/plain
 rtl/darwin/pmutext.inc svneol=native#text/plain
@@ -4980,12 +5059,14 @@ rtl/inc/dosh.inc svneol=native#text/plain
 rtl/inc/dynarr.inc svneol=native#text/plain
 rtl/inc/dynarrh.inc svneol=native#text/plain
 rtl/inc/dynlibs.pas svneol=native#text/plain
-rtl/inc/elfres32.inc svneol=native#text/plain
 rtl/inc/except.inc svneol=native#text/plain
 rtl/inc/exeinfo.pp svneol=native#text/plain
+rtl/inc/extres.inc svneol=native#text/plain
 rtl/inc/fexpand.inc svneol=native#text/plain
 rtl/inc/file.inc svneol=native#text/plain
 rtl/inc/filerec.inc svneol=native#text/plain
+rtl/inc/fpextres.pp svneol=native#text/plain
+rtl/inc/fpintres.pp svneol=native#text/plain
 rtl/inc/gencurr.inc svneol=native#text/plain
 rtl/inc/generic.inc svneol=native#text/plain
 rtl/inc/genmath.inc svneol=native#text/plain
@@ -4998,6 +5079,7 @@ rtl/inc/heaph.inc svneol=native#text/plain
 rtl/inc/heaptrc.pp svneol=native#text/plain
 rtl/inc/innr.inc svneol=native#text/plain
 rtl/inc/int64.inc svneol=native#text/plain
+rtl/inc/intres.inc svneol=native#text/plain
 rtl/inc/keyboard.inc svneol=native#text/plain
 rtl/inc/keybrdh.inc svneol=native#text/plain
 rtl/inc/keyscan.inc svneol=native#text/plain
@@ -7546,7 +7628,15 @@ tests/test/units/system/tres.pp -text
 tests/test/units/system/tres1.rc -text
 tests/test/units/system/tres1.res -text
 tests/test/units/system/tres1.txt -text
+tests/test/units/system/tres1_it.txt svneol=native#text/plain
+tests/test/units/system/tres2.pp svneol=native#text/plain
 tests/test/units/system/tres2.txt -text
+tests/test/units/system/tres2ext.pp svneol=native#text/plain
+tests/test/units/system/tres3.pp svneol=native#text/plain
+tests/test/units/system/tres3ext.pp svneol=native#text/plain
+tests/test/units/system/tresb.rc svneol=native#text/plain
+tests/test/units/system/tresb.res -text
+tests/test/units/system/tresext.pp svneol=native#text/plain
 tests/test/units/system/tround.pp svneol=native#text/plain
 tests/test/units/system/tseg.pp svneol=native#text/plain
 tests/test/units/system/tsetstr.pp svneol=native#text/plain
@@ -9011,12 +9101,17 @@ utils/fpcm/printmakefilefpcrequirements.sh svneol=native#text/plain
 utils/fpcm/readme.txt svneol=native#text/plain
 utils/fpcres/Makefile svneol=native#text/plain
 utils/fpcres/Makefile.fpc svneol=native#text/plain
-utils/fpcres/elfbfd.pas svneol=native#text/plain
-utils/fpcres/elfres.pas svneol=native#text/plain
-utils/fpcres/elfresfix.pas svneol=native#text/plain
-utils/fpcres/fpcres.lpi svneol=native#text/plain
 utils/fpcres/fpcres.pas svneol=native#text/plain
-utils/fpcres/resptrs.as -text
+utils/fpcres/msghandler.pas svneol=native#text/plain
+utils/fpcres/paramparser.pas svneol=native#text/plain
+utils/fpcres/sourcehandler.pas svneol=native#text/plain
+utils/fpcres/target.pas svneol=native#text/plain
+utils/fpcreslipo/Makefile svneol=native#text/plain
+utils/fpcreslipo/Makefile.fpc svneol=native#text/plain
+utils/fpcreslipo/fpcreslipo.pp svneol=native#text/plain
+utils/fpcreslipo/msghandler.pp svneol=native#text/plain
+utils/fpcreslipo/paramparser.pp svneol=native#text/plain
+utils/fpcreslipo/sourcehandler.pp svneol=native#text/plain
 utils/fpdoc/COPYING -text
 utils/fpdoc/Makefile svneol=native#text/plain
 utils/fpdoc/Makefile.fpc svneol=native#text/plain

+ 223 - 226
compiler/comprsrc.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Florian Klaempfl
+    Copyright (c) 1998-2008 by Florian Klaempfl
 
     Handles the resource files handling
 
@@ -26,7 +26,7 @@ unit comprsrc;
 interface
 
   uses
-    Systems, cstreams;
+    Systems, cstreams, Script;
 
 type
    tresoutput = (roRES, roOBJ);
@@ -34,22 +34,33 @@ type
    tresourcefile = class(TAbstractResourceFile)
    private
       fname : ansistring;
+   protected
+      function SetupCompilerArguments(output: tresoutput; const OutName :
+      ansistring; respath: ansistring; out ObjUsed : boolean) : ansistring; virtual;
    public
       constructor Create(const fn : ansistring);override;
-      procedure Compile(output: tresoutput; const OutName: ansistring);virtual;
+      function Compile(output: tresoutput; const OutName: ansistring) : boolean; virtual;
       procedure PostProcessResourcefile(const s : ansistring);virtual;
       function IsCompiled(const fn : ansistring) : boolean;virtual;
       procedure Collect(const fn : ansistring);virtual;
+      procedure EndCollect; virtual;
    end;
    
    TWinLikeResourceFile = class(tresourcefile)
    private
-      FOut: TCFileStream;
-      FLastIconID: longint;
-      FLastCursorID: longint;
+      fResScript : TScript;
+      fScriptName : ansistring;
+      fCollectCount : integer;
+   protected
+      function SetupCompilerArguments(output: tresoutput; const OutName :
+        ansistring; respath: ansistring; out ObjUsed : boolean) : ansistring; override;
    public
+      constructor Create(const fn : ansistring);override;
+      destructor Destroy; override;
+      function Compile(output: tresoutput; const OutName: ansistring) : boolean; override;
       function IsCompiled(const fn : ansistring) : boolean;override;
       procedure Collect(const fn : ansistring);override;
+      procedure EndCollect; override;
    end;
 
 procedure CompileResourceFiles;
@@ -64,11 +75,7 @@ implementation
 uses
   SysUtils,
   cutils,cfileutl,cclasses,
-  Globtype,Globals,Verbose,Fmodule,
-  Script;
-  
-const
-  GlobalResName = 'fpc-res';
+  Globtype,Globals,Verbose,Fmodule, comphook;
 
 {****************************************************************************
                               TRESOURCEFILE
@@ -90,7 +97,6 @@ begin
   Result:=CompareText(ExtractFileExt(fn), target_info.resobjext) = 0;
 end;
 
-
 procedure tresourcefile.Collect(const fn: ansistring);
 begin
   if fn='' then
@@ -99,34 +105,62 @@ begin
   Compile(roOBJ, ChangeFileExt(fn, target_info.resobjext));
 end;
 
+procedure tresourcefile.EndCollect;
+begin
+
+end;
+
+function tresourcefile.SetupCompilerArguments(output: tresoutput; const OutName
+  : ansistring; respath: ansistring; out ObjUsed : boolean) : ansistring;
+var
+  s : TCmdStr;
+begin
+  if output=roRES then
+    begin
+      s:=target_res.rccmd;
+      Replace(s,'$RES',maybequoted(OutName));
+      Replace(s,'$RC',maybequoted(fname));
+      ObjUsed:=False;
+    end
+  else
+    begin
+      s:=target_res.rescmd;
+      ObjUsed:=(pos('$OBJ',s)>0);
+      Replace(s,'$OBJ',maybequoted(OutName));
+      Replace(s,'$RES',maybequoted(fname));
+    end;
+  Result:=s;
+end;
 
-procedure tresourcefile.compile(output: tresoutput; const OutName: ansistring);
+function tresourcefile.compile(output: tresoutput; const OutName: ansistring)
+  : boolean;
 
   Function SelectBin(Const Bin1,Bin2 : String) : String;
-  
   begin
     If (Bin1<>'') then
       SelectBin:=Bin1
     else
-      SelectBin:=Bin2;  
+      SelectBin:=Bin2;
   end;
-  
+
 var
   respath,
-  srcfilepath,
-  preprocessorbin,
   s,
   bin,
   resbin   : TCmdStr;
   resfound,
   objused  : boolean;
 begin
+  Result:=true;
   if output=roRES then
     Bin:=SelectBin(RCCompiler,target_res.rcbin)
   else
     Bin:=SelectBin(ResCompiler,target_res.resbin);
   if bin='' then
+  begin
+    Result:=false;
     exit;
+  end;
   resfound:=false;
   if utilsdirectory<>'' then
     resfound:=FindFile(utilsprefix+bin+source_info.exeext,utilsdirectory,false,resbin);
@@ -136,39 +170,14 @@ begin
   respath:=ExtractFilePath(resbin);
   if (not resfound) and not(cs_link_nolink in current_settings.globalswitches) then
    begin
-     Message(exec_e_res_not_found);
+     Message1(exec_e_res_not_found, bin);
      current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
+     Result:=false;
    end;
-  srcfilepath:=ExtractFilePath(current_module.mainsource^);
-  if output=roRES then
-    begin
-      s:=target_res.rccmd;
-      Replace(s,'$RES',maybequoted(OutName));
-      Replace(s,'$RC',maybequoted(fname));
-      ObjUsed:=False;
-    end
-  else
-    begin
-      s:=target_res.rescmd;
-      ObjUsed:=(pos('$OBJ',s)>0);
-      Replace(s,'$OBJ',maybequoted(OutName));
-      Replace(s,'$RES',maybequoted(fname));
-    end;
-  { windres doesn't like empty include paths }
-  if respath='' then
-    respath:='.';
-  Replace(s,'$INC',maybequoted(respath));
-  if (target_res.resbin='windres') then
-   begin
-     if (srcfilepath<>'') then
-       s:=s+' --include '+maybequoted(srcfilepath);
-     { try to find a preprocessor }
-     preprocessorbin := respath+'cpp'+source_info.exeext;
-     if FileExists(preprocessorbin,true) then
-       s:=s+' --preprocessor='+preprocessorbin;
-   end;
+  s:=SetupCompilerArguments(output,OutName,respath,objused);
 { Execute the command }
-  if not (cs_link_nolink in current_settings.globalswitches) then
+{ Always try to compile resources. but don't complain if cs_link_nolink }
+  if resfound then
    begin
      Message1(exec_i_compilingresource,fname);
      Message2(exec_d_resbin_params,resbin,s);
@@ -176,39 +185,136 @@ begin
      try
        if ExecuteProcess(resbin,s) <> 0 then
        begin
-         Message(exec_e_error_while_linking);
+         if not (cs_link_nolink in current_settings.globalswitches) then
+           Message(exec_e_error_while_compiling_resources);
          current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
+         Result:=false;
        end;
      except
        on E:EOSError do
        begin
-         Message(exec_e_cant_call_linker);
+         if not (cs_link_nolink in current_settings.globalswitches) then
+           Message1(exec_e_cant_call_resource_compiler, resbin);
          current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
+         Result:=false;
        end
      end;
     end;
-  if output=roOBJ then
-    PostProcessResourcefile(OutName);
-  { Update asmres when externmode is set }
-  if cs_link_nolink in current_settings.globalswitches then
-    AsmRes.AddLinkCommand(resbin,s,'');
-  if (output=roOBJ) and ObjUsed then
+  { Update asmres when externmode is set and resource compiling failed }
+  if (not Result) and (cs_link_nolink in current_settings.globalswitches) then
+    AsmRes.AddLinkCommand(resbin,s,OutName);
+  if Result and (output=roOBJ) and ObjUsed then
     current_module.linkunitofiles.add(OutName,link_always);
 end;
 
+constructor TWinLikeResourceFile.Create(const fn : ansistring);
+begin
+  inherited Create(fn);
+  fResScript:=nil;
+  fCollectCount:=0;
+  if (tf_use_8_3 in target_info.flags) then
+    fScriptName:=ChangeFileExt(fn,'.rls')
+  else
+    fScriptName:=ChangeFileExt(fn,'.reslst');
+end;
+
+destructor TWinLikeResourceFile.Destroy;
+begin
+  if fResScript<>nil then
+    fResScript.Free;
+  inherited;
+end;
+
+function TWinLikeResourceFile.SetupCompilerArguments(output: tresoutput; const
+  OutName : ansistring; respath : ansistring; out ObjUsed : boolean) : ansistring;
+var
+  srcfilepath,
+  preprocessorbin,
+  s : TCmdStr;
+  arch : ansistring;
+begin
+  srcfilepath:=ExtractFilePath(current_module.mainsource^);
+  if output=roRES then
+    begin
+      s:=target_res.rccmd;
+      Replace(s,'$RES',maybequoted(OutName));
+      Replace(s,'$RC',maybequoted(fname));
+      ObjUsed:=False;
+    end
+  else
+    begin
+      s:=target_res.rescmd;
+      if (res_external_file in target_res.resflags) then
+        ObjUsed:=false
+      else
+        ObjUsed:=(pos('$OBJ',s)>0);
+      Replace(s,'$OBJ',maybequoted(OutName));
+      arch:=cpu2str[target_cpu];
+      //Differentiate between arm and armeb
+      if (source_info.cpu=cpu_arm) and (source_info.endian=endian_big) then
+        arch:=arch+'eb';
+      Replace(s,'$ARCH',arch);
+      case target_info.endian of
+        endian_little : Replace(s,'$ENDIAN','littleendian');
+        endian_big : Replace(s,'$ENDIAN','bigendian');
+      end;
+      //call resource compiler with debug switch
+      if (status.verbosity and V_Debug)<>0 then
+        Replace(s,'$DBG','-v')
+      else
+        Replace(s,'$DBG','');
+      if fCollectCount=0 then
+        s:=s+' '+maybequoted(fname)
+      else
+        s:=s+' @'+fScriptName;
+    end;
+  { windres doesn't like empty include paths }
+  if respath='' then
+    respath:='.';
+  Replace(s,'$INC',maybequoted(respath));
+  if (output=roRes) and (target_res.rcbin='windres') then
+  begin
+    if (srcfilepath<>'') then
+      s:=s+' --include '+maybequoted(srcfilepath);
+    { try to find a preprocessor }
+    preprocessorbin := respath+'cpp'+source_info.exeext;
+    if FileExists(preprocessorbin,true) then
+      s:=s+' --preprocessor='+preprocessorbin;
+  end;
+  Result:=s;
+end;
+
+function TWinLikeResourceFile.compile(output: tresoutput;
+  const OutName: ansistring) : boolean;
+begin
+  Result:=inherited compile(output,OutName);
+  //delete fpc-res.lst file if things went well
+  if Result and (output=roOBJ) then
+    DeleteFile(fScriptName);
+end;
 
 function TWinLikeResourceFile.IsCompiled(const fn: ansistring): boolean;
 const
   ResSignature : array [1..32] of byte =
   ($00,$00,$00,$00,$20,$00,$00,$00,$FF,$FF,$00,$00,$FF,$FF,$00,$00,
    $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00);
+  dfmexts : array[1..3] of string[4] = ('.lfm', '.dfm', '.xfm');
 var
   f : file;
   oldfmode : byte;
   buf: array[1..32] of byte;
   i: longint;
+  ext : shortstring;
 begin
-  Result:=CompareText(ExtractFileExt(fn), target_info.resext) = 0;
+  ext:=lower(ExtractFileExt(fn));
+  Result:=CompareText(ext, target_info.resext) = 0;
+  if not Result then
+    for i:=1 to high(dfmexts) do
+    begin
+      Result:=CompareText(ext, dfmexts[i]) = 0;
+      if Result then break;
+    end;
+
   if Result or not FileExists(fn, False) then exit;
   oldfmode:=Filemode;
   Filemode:=0;
@@ -228,164 +334,62 @@ begin
   Result:=True;
 end;
 
-
 procedure TWinLikeResourceFile.Collect(const fn: ansistring);
-const
-  zeroes: array[1..3] of byte = (0,0,0);
+begin
+  if fResScript=nil then
+    fResScript:=TScript.Create(fScriptName);
+  fResScript.Add(fn);
+  inc(fCollectCount);
+end;
 
-type
-  TResHeader = packed record
-    DataSize: dword;
-    HeaderSize: dword;
-    ResTypeFlag: word;
-    ResTypeID: word;
-  end;
-  
-  PIconHeader = ^TIconHeader;
-  TIconHeader = packed record
-    Reserved: word;
-    wType: word;
-    wCount: word;
-  end;
-  
-  PIconDir = ^TIconDir;
-  TIconDir = packed record
-    bWidth: byte;
-    bHeight: byte;
-    bColorCount: byte;
-    bReserved: byte;
-    wPlanes: word;
-    wBitCount: word;
-    lBytesInRes: dword;
-    wNameOrdinal: word;
+procedure TWinLikeResourceFile.EndCollect;
+begin
+  if fResScript<>nil then
+  begin
+    fResScript.WriteToDisk;
+    FreeAndNil(fResScript);
+    Compile(roOBJ,ChangeFileExt(fname,target_info.resobjext));
   end;
+end;
+
 
+function CopyResFile(inf,outf : TCmdStr) : boolean;
 var
-  fs: TCFileStream;
-  i, sz, rsz, MaxIconID, MaxCursorID: longint;
-  hdr: TResHeader;
-  P: pointer;
-  PData: PIconHeader;
-  PDir: PIconDir;
-  ResNameBuf: array[0..1] of word;
+  src,dst : TCFileStream;
 begin
-  if fn='' then
+  { Copy .res file to units output dir. }
+  Result:=false;
+  src:=TCFileStream.Create(inf,fmOpenRead or fmShareDenyNone);
+  if CStreamError<>0 then
     begin
-      if FOut<>nil then
-        begin
-          FOut.Free;
-          Compile(roOBJ,ChangeFileExt(fname,target_info.resobjext));
-        end;
-    end
-  else
-    try
-      fs:=TCFileStream.Create(fn,fmOpenRead or fmShareDenyNone);
-      if CStreamError<>0 then
-        begin
-          fs.Free;
-          Comment(V_Error,'Can''t open resource file: '+fn);
-          Include(current_settings.globalswitches, cs_link_nolink);
-          exit;
-        end;
-      if FOut=nil then
-        begin
-          FOut:=TCFileStream.Create(fname,fmCreate);
-          { writing res signature }
-          FOut.CopyFrom(fs, 32);
-        end
-      else
-        fs.Seek(32, soFromBeginning);
-      sz:=fs.Size;
-      MaxIconID := 0;
-      MaxCursorID := 0;
-      repeat
-        fs.ReadBuffer(hdr, SizeOf(hdr));
-        FOut.WriteBuffer(hdr, SizeOf(hdr));
-        rsz:=hdr.HeaderSize + hdr.DataSize - SizeOf(hdr);
-        if fs.Position + rsz > sz then
-          begin
-            Comment(V_Error,'Invalid resource file: '+fn);
-            Include(current_settings.globalswitches, cs_link_nolink);
-            fs.Free;
-            exit;
-          end;
-        { Adjusting cursor and icon IDs }
-        if hdr.ResTypeFlag = $FFFF then       { resource type is ordinal }
-          case hdr.ResTypeID of
-            1, 3:
-              { cursor or icon resource }
-              begin
-                fs.ReadBuffer(ResNameBuf, SizeOf(ResNameBuf));
-                if ResNameBuf[0] = $FFFF then   { resource name is ordinal }
-                  if hdr.ResTypeID = 1 then
-                    begin
-                      if ResNameBuf[1] > MaxCursorID then
-                        MaxCursorID:=ResNameBuf[1];
-                      Inc(ResNameBuf[1], FLastCursorID);
-                    end
-                  else
-                    begin
-                      if ResNameBuf[1] > MaxIconID then
-                        MaxIconID:=ResNameBuf[1];
-                      Inc(ResNameBuf[1], FLastIconID);
-                    end;
-                FOut.WriteBuffer(ResNameBuf, SizeOf(ResNameBuf));
-                Dec(rsz, SizeOf(ResNameBuf));
-              end;
-            12, 14:
-              { cursor or icon group resource }
-              begin
-                GetMem(P, rsz);
-                fs.ReadBuffer(P^, rsz);
-                PData := PIconHeader(P + hdr.HeaderSize - sizeof(hdr));
-                PDir := PIconDir(Pointer(PData) + sizeof(TIconHeader));
-                for i := 0 to PData^.wCount-1 do
-                  begin
-                    if hdr.ResTypeID = 12 then
-                      Inc(PDir^.wNameOrdinal, FLastCursorID)
-                    else
-                      Inc(PDir^.wNameOrdinal, FLastIconID);
-                    Inc(PDir);
-                  end;
-                FOut.WriteBuffer(P^, rsz);
-                rsz:=0;
-                FreeMem(P);
-              end;
-          end;
-        { copy rest of the resource data }
-        FOut.CopyFrom(fs, rsz);
-        { align resource to dword }
-        i:=4 - FOut.Position mod 4;
-        if i<4 then
-          FOut.WriteBuffer(zeroes, i);
-        { position to the next resource }
-        i:=4 - fs.Position mod 4;
-        if i<4 then
-          fs.Seek(i, soFromCurrent);
-      until fs.Position + SizeOf(hdr) >= sz;
-      fs.Free;
-      Inc(FLastCursorID, MaxCursorID);
-      Inc(FLastIconID, MaxIconID);
-    except
-      on E:EOSError do begin
-        Comment(V_Error,'Error processing resource file: '+fn+': '+E.Message);
-        Include(current_settings.globalswitches, cs_link_nolink);
-      end;
+      Message1(exec_e_cant_open_resource_file, src.FileName);
+      Include(current_settings.globalswitches, cs_link_nolink);
+      exit;
     end;
+  dst:=TCFileStream.Create(current_module.outputpath^+outf,fmCreate);
+  if CStreamError<>0 then
+    begin
+      Message1(exec_e_cant_write_resource_file, dst.FileName);
+      Include(current_settings.globalswitches, cs_link_nolink);
+      exit;
+    end;
+  dst.CopyFrom(src,src.Size);
+  dst.Free;
+  src.Free;
+  Result:=true;
 end;
-
-
+ 
 procedure CompileResourceFiles;
 var
   resourcefile : tresourcefile;
   res: TCmdStrListItem;
   p,s : TCmdStr;
-  src,dst : TCFileStream;
   outfmt : tresoutput;
 begin
-  { OS/2 (EMX) must be processed elsewhere (in the linking/binding stage).
-    same with MacOS}
-  if target_info.system in [system_i386_os2,system_i386_emx,system_powerpc_macos] then exit;
+  { Don't do anything for systems supporting resources without using resource
+    file classes (e.g. Mac OS). They process resources elsewhere. }
+  if (target_info.res<>res_none) and (target_res.resourcefileclass=nil) then
+    exit;
 
   p:=ExtractFilePath(current_module.mainsource^);
   res:=TCmdStrListItem(current_module.ResourceFiles.First);
@@ -396,37 +400,27 @@ begin
       s:=res.FPStr;
       if not path_absolute(s) then
         s:=p+s;
+      if not FileExists(s, True) then
+        begin
+          Message1(exec_e_cant_open_resource_file, s);
+          Include(current_settings.globalswitches, cs_link_nolink);
+          exit;
+        end;
       resourcefile:=TResourceFile(resinfos[target_info.res]^.resourcefileclass.create(s));
       if resourcefile.IsCompiled(s) then
         begin
           resourcefile.free;
-          if CompareText(current_module.outputpath^, p) <> 0 then
+          if AnsiCompareText(current_module.outputpath^, p) <> 0 then
             begin
-              { Copy .res file to units output dir }
-              res.FPStr:=ExtractFileName(res.FPStr);
-              src:=TCFileStream.Create(s,fmOpenRead or fmShareDenyNone);
-              if CStreamError<>0 then
-                begin
-                  Comment(V_Error,'Can''t open resource file: '+src.FileName);
-                  Include(current_settings.globalswitches, cs_link_nolink);
-                  exit;
-                end;
-              dst:=TCFileStream.Create(current_module.outputpath^+res.FPStr,fmCreate);
-              if CStreamError<>0 then
-                begin
-                  Comment(V_Error,'Can''t create resource file: '+dst.FileName);
-                  Include(current_settings.globalswitches, cs_link_nolink);
-                  exit;
-                end;
-              dst.CopyFrom(src,src.Size);
-              dst.Free;
-              src.Free;
+              { Copy .res file to units output dir. Otherwise .res file will not be found
+                when only compiled units path is available }
+              if not CopyResFile(s,ExtractFileName(res.FPStr)) then exit;
             end;
         end
       else
         begin
           res.FPStr:=ExtractFileName(res.FPStr);
-          if target_res.rcbin='' then
+          if (target_res.rcbin='') and (RCCompiler='') then
             begin
               { if target does not have .rc to .res compiler, create obj }
               outfmt:=roOBJ;
@@ -474,11 +468,14 @@ var
   hp : tused_unit;
   s : TCmdStr;
 begin
-  if (target_info.res=res_none) or (target_res.rcbin='') then
-    exit;
-  if cs_link_nolink in current_settings.globalswitches then
-    exit;
-  s:=main_module.outputpath^+GlobalResName+target_info.resext;
+  if (target_info.res=res_none) or ((target_res.resbin='')
+    and (ResCompiler='')) then
+      exit;
+//  if cs_link_nolink in current_settings.globalswitches then
+//    exit;
+  s:=ChangeFileExt(current_module.ppufilename^,target_info.resobjext);
+  if (res_arch_in_file_name in target_res.resflags) then
+    s:=ChangeFileExt(s,'.'+cpu2str[target_cpu]+target_info.resobjext);
   resourcefile:=TResourceFile(resinfos[target_info.res]^.resourcefileclass.create(s));
   hp:=tused_unit(usedunits.first);
   while assigned(hp) do
@@ -488,7 +485,7 @@ begin
     end;
   ProcessModule(current_module);
   { Finish collection }
-  resourcefile.Collect('');
+  resourcefile.EndCollect;
   resourcefile.free;
 end;
 

+ 1 - 0
compiler/fmodule.pas

@@ -197,6 +197,7 @@ interface
        compiled_module   : tmodule;     { Current module which is compiled }
        usedunits         : tlinkedlist; { Used units for this program }
        loaded_units      : tlinkedlist; { All loaded units }
+       unloaded_units    : tlinkedlist; { Units removed from loaded_units, to be freed }
        SmartLinkOFiles   : TCmdStrList; { List of .o files which are generated,
                                           used to delete them after linking }
 

+ 24 - 5
compiler/msg/errore.msg

@@ -1,6 +1,6 @@
 #
 #   This file is part of the Free Pascal Compiler
-#   Copyright (c) 1999-2006 by the Free Pascal Development team
+#   Copyright (c) 1999-2008 by the Free Pascal Development team
 #
 #   English (default) Language File for Free Pascal
 #
@@ -2015,7 +2015,7 @@ asmw_e_64bit_not_supported=08021_E_Asm: 64 Bit operands not supported
 #
 # Executing linker/assembler
 #
-# 09028 is the last used one
+# 09032 is the last used one
 #
 # BeginOfTeX
 %
@@ -2078,7 +2078,7 @@ exec_e_dll_not_supported=09019_E_Creation of Dynamic/Shared Libraries not suppor
 % not yet implemented in the compiler.
 exec_i_closing_script=09020_I_Closing script $1
 % Informational message showing when the external assembling an linking script is finished.
-exec_e_res_not_found=09021_E_resource compiler not found, switching to external mode
+exec_e_res_not_found=09021_E_resource compiler "$1" not found, switching to external mode
 % An external resource compiler was not found, the compiler will produce a script that
 % can be used to assemble, compile resources and link or postprocess the program.
 exec_i_compilingresource=09022_I_Compiling resource $1
@@ -2088,13 +2088,23 @@ exec_t_unit_not_static_linkable_switch_to_smart=09023_T_unit $1 can't be statica
 exec_t_unit_not_smart_linkable_switch_to_static=09024_T_unit $1 can't be smart linked, switching to static linking
 % Smart linking was requested, but a unit which is not smart-linkable was used.
 exec_t_unit_not_shared_linkable_switch_to_static=09025_T_unit $1 can't be shared linked, switching to static linking
-% Shared linking was requested, but a unit which is not shared-linkable  was used.
+% Shared linking was requested, but a unit which is not shared-linkable was used.
 exec_e_unit_not_smart_or_static_linkable=09026_E_unit $1 can't be smart or static linked
 % Smart or static linking was requested, but a unit which cannot be used for either  was used.
 exec_e_unit_not_shared_or_static_linkable=09027_E_unit $1 can't be shared or static linked
 % Shared or static linking was requested, but a unit which cannot be used for either  was used.
 exec_d_resbin_params=09028_D_Calling resource compiler "$1" with "$2" as command line
 % An informational message showing which command-line is used for the resource compiler.
+exec_e_error_while_compiling_resources=09029_E_Error while compiling resources
+% The resource compiler or converter returned an error
+exec_e_cant_call_resource_compiler=09030_E_Can't call the resource compiler "$1", switching to external mode
+% An error occurred when calling a resource compiler, the compiler will produce
+% a script that can be used to assemble, compile resources and link or
+% postprocess the program.
+exec_e_cant_open_resource_file=09031_E_Can't open resource file "$1"
+% An error occurred resource file can not be opened
+exec_e_cant_write_resource_file=09032_E_Can't write resource file "$1"
+% An error occurred resource file can not be written
 %\end{description}
 # EndOfTeX
 
@@ -2128,7 +2138,7 @@ execinfo_x_stackcommit=09134_X_Stack space committed: $1 bytes
 #
 # Unit loading
 #
-# 10059 is the last used one
+# 10060 is the last used one
 #
 # BeginOfTeX
 % \section{Unit loading messages.}
@@ -2318,6 +2328,9 @@ unit_u_skipping_reresolving_unit=10059_U_Skipping re-resolving unit $1, still lo
 % When you use the \var{-vu} flag, the compiler warns that it
 % skips to recalculate the internal data of the unit because there
 % is no data to recalculate
+unit_u_unload_resunit=10060_U_Unloading resource unit $1 (not needed) 
+% When you use the \var{-vu} flag, the compiler warns that it is unloading the 
+% resource handling unit, since no resources are used.
 % \end{description}
 # EndOfTeX
 
@@ -2690,10 +2703,16 @@ A*2WC_Specify console type application (Windows)
 P*2WC_Specify console type application (Classic Mac OS)
 3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)
 A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)
+3*2We_Use external resources (Darwin)
+P*2We_Use external resources (Darwin)
+p*2We_Use external resources (Darwin)
 3*2WF_Specify full-screen type application (EMX, OS/2)
 3*2WG_Specify graphic type application (EMX, OS/2, Windows)
 A*2WG_Specify graphic type application (Windows)
 P*2WG_Specify graphic type application (Classic Mac OS)
+3*2Wi_Use internal resources (Darwin)
+P*2Wi_Use internal resources (Darwin)
+p*2Wi_Use internal resources (Darwin)
 3*2WN_Do not generate relocation code, needed for debugging (Windows)
 A*2WN_Do not generate relocation code, needed for debugging (Windows)
 3*2WR_Generate relocation code (Windows)

+ 7 - 2
compiler/msgidx.inc

@@ -639,6 +639,10 @@ const
   exec_e_unit_not_smart_or_static_linkable=09026;
   exec_e_unit_not_shared_or_static_linkable=09027;
   exec_d_resbin_params=09028;
+  exec_e_error_while_compiling_resources=09029;
+  exec_e_cant_call_resource_compiler=09030;
+  exec_e_cant_open_resource_file=09031;
+  exec_e_cant_write_resource_file=09032;
   execinfo_f_cant_process_executable=09128;
   execinfo_f_cant_open_executable=09129;
   execinfo_x_codesize=09130;
@@ -704,6 +708,7 @@ const
   unit_u_registering_new_unit=10057;
   unit_u_reresolving_unit=10058;
   unit_u_skipping_reresolving_unit=10059;
+  unit_u_unload_resunit=10060;
   option_usage=11000;
   option_only_one_source_support=11001;
   option_def_only_for_os2=11002;
@@ -745,9 +750,9 @@ const
   option_info=11024;
   option_help_pages=11025;
 
-  MsgTxtSize = 46251;
+  MsgTxtSize = 46724;
 
   MsgIdxMax : array[1..20] of longint=(
-    24,87,247,84,64,50,108,22,135,60,
+    24,87,247,84,64,50,108,22,135,61,
     42,1,1,1,1,1,1,1,1,1
   );

+ 97 - 84
compiler/msgtxt.inc

@@ -1,7 +1,7 @@
 {$ifdef Delphi}
-const msgtxt : array[0..000192] of string[240]=(
+const msgtxt : array[0..000194] of string[240]=(
 {$else Delphi}
-const msgtxt : array[0..000192,1..240] of char=(
+const msgtxt : array[0..000194,1..240] of char=(
 {$endif Delphi}
   '01000_T_Compiler: $1'#000+
   '01001_D_Compiler OS: $1'#000+
@@ -705,24 +705,29 @@ const msgtxt : array[0..000192,1..240] of char=(
   '09018_E_Creation of Executables not supported'#000+
   '09019_E_Creation of Dynamic/Shared Libraries no','t supported'#000+
   '09020_I_Closing script $1'#000+
-  '09021_E_resource compiler not found, switching to external mode'#000+
+  '09021_E_resource compiler "$1" not found, switching to external mode'#000+
   '09022_I_Compiling resource $1'#000+
   '09023_T_unit $1 can'#039't be statically linked, switching to smart lin'+
   'king'#000+
-  '09024_T_unit $1 can'#039't be smart linked',', switching to static linki'+
+  '09024_T_unit $1 can'#039't be smart l','inked, switching to static linki'+
   'ng'#000+
   '09025_T_unit $1 can'#039't be shared linked, switching to static linkin'+
   'g'#000+
   '09026_E_unit $1 can'#039't be smart or static linked'#000+
   '09027_E_unit $1 can'#039't be shared or static linked'#000+
-  '09028_D_Calling resource compiler "$1" with "','$2" as command line'#000+
-  '09128_F_Can'#039't post process executable $1'#000+
+  '09028_D_Calling resource compiler "$1" w','ith "$2" as command line'#000+
+  '09029_E_Error while compiling resources'#000+
+  '09030_E_Can'#039't call the resource compiler "$1", switching to extern'+
+  'al mode'#000+
+  '09031_E_Can'#039't open resource file "$1"'#000+
+  '09032_E_Can'#039't write resource file "$1"'#000+
+  '09128_F_Can'#039't post proce','ss executable $1'#000+
   '09129_F_Can'#039't open executable $1'#000+
   '09130_X_Size of Code: $1 bytes'#000+
   '09131_X_Size of initialized data: $1 bytes'#000+
   '09132_X_Size of uninitialized data: $1 bytes'#000+
-  '09133_X_Stack space reserve','d: $1 bytes'#000+
-  '09134_X_Stack space committed: $1 bytes'#000+
+  '09133_X_Stack space reserved: $1 bytes'#000+
+  '09134_X_Stack space committed: $','1 bytes'#000+
   '10000_T_Unitsearch: $1'#000+
   '10001_T_PPU Loading $1'#000+
   '10002_U_PPU Name: $1'#000+
@@ -730,67 +735,69 @@ const msgtxt : array[0..000192,1..240] of char=(
   '10004_U_PPU Crc: $1'#000+
   '10005_U_PPU Time: $1'#000+
   '10006_U_PPU File too short'#000+
-  '10007_U_PPU Invalid Header (no ','PPU at the begin)'#000+
-  '10008_U_PPU Invalid Version $1'#000+
+  '10007_U_PPU Invalid Header (no PPU at the begin)'#000+
+  '10008_U_PPU Invalid Versio','n $1'#000+
   '10009_U_PPU is compiled for another processor'#000+
   '10010_U_PPU is compiled for an other target'#000+
   '10011_U_PPU Source: $1'#000+
   '10012_U_Writing $1'#000+
   '10013_F_Can'#039't Write PPU-File'#000+
-  '10014_F_Error reading PPU-File',#000+
+  '10014_F_Error reading PPU-File'#000+
   '10015_F_unexpected end of PPU-File'#000+
-  '10016_F_Invalid PPU-File entry: $1'#000+
+  '10016_F_','Invalid PPU-File entry: $1'#000+
   '10017_F_PPU Dbx count problem'#000+
   '10018_E_Illegal unit name: $1'#000+
   '10019_F_Too much units'#000+
   '10020_F_Circular unit reference between $1 and $2'#000+
-  '10021_F_Can'#039't compile unit $1, no so','urces available'#000+
-  '10022_F_Can'#039't find unit $1 used by $2'#000+
+  '10021_F_Can'#039't compile unit $1, no sources available'#000+
+  '10022_F_Can'#039't find unit $1 u','sed by $2'#000+
   '10023_W_Unit $1 was not found but $2 exists'#000+
   '10024_F_Unit $1 searched but $2 found'#000+
   '10025_W_Compiling the system unit requires the -Us switch'#000+
-  '10026_F_There were $1 errors compiling module,',' stopping'#000+
-  '10027_U_Load from $1 ($2) unit $3'#000+
+  '10026_F_There were $1 errors compiling module, stopping'#000+
+  '10027_U_Load from $1 ($2) unit $3'#000,
   '10028_U_Recompiling $1, checksum changed for $2'#000+
   '10029_U_Recompiling $1, source found only'#000+
   '10030_U_Recompiling unit, static lib is older than ppufile'#000+
-  '10031_U_Recompiling unit, shared lib is older t','han ppufile'#000+
-  '10032_U_Recompiling unit, obj and asm are older than ppufile'#000+
+  '10031_U_Recompiling unit, shared lib is older than ppufile'#000+
+  '10032_U_Recompiling unit, obj an','d asm are older than ppufile'#000+
   '10033_U_Recompiling unit, obj is older than asm'#000+
   '10034_U_Parsing interface of $1'#000+
   '10035_U_Parsing implementation of $1'#000+
   '10036_U_Second load for unit $1'#000+
-  '10037_U_PPU Check ','file $1 time $2'#000+
-  '10040_W_Can'#039't recompile unit $1, but found modifed include files'#000+
+  '10037_U_PPU Check file $1 time $2'#000+
+  '10040_W_Can'#039't recompile unit',' $1, but found modifed include files'+
+  #000+
   '10041_U_File $1 is newer than PPU file $2'#000+
   '10042_U_Trying to use a unit which was compiled with a different FPU m'+
   'ode'#000+
   '10043_U_Loading interface units from $1'#000+
-  '100','44_U_Loading implementation units from $1'#000+
-  '10045_U_Interface CRC changed for unit $1'#000+
+  '10044_U_Loading implementation units from $1'#000+
+  '10','045_U_Interface CRC changed for unit $1'#000+
   '10046_U_Implementation CRC changed for unit $1'#000+
   '10047_U_Finished compiling unit $1'#000+
   '10048_U_Add dependency of $1 to $2'#000+
   '10049_U_No reload, is caller: $1'#000+
-  '10050_','U_No reload, already in second compile: $1'#000+
-  '10051_U_Flag for reload: $1'#000+
+  '10050_U_No reload, already in second compile: $1'#000+
+  '1','0051_U_Flag for reload: $1'#000+
   '10052_U_Forced reloading'#000+
   '10053_U_Previous state of $1: $2'#000+
   '10054_U_Already compiling $1, setting second compile'#000+
   '10055_U_Loading unit $1'#000+
   '10056_U_Finished loading unit $1'#000+
-  '1','0057_U_Registering new unit $1'#000+
-  '10058_U_Re-resolving unit $1'#000+
+  '10057_U_Registering new unit $1'#000+
+  '10058_U_Re-re','solving unit $1'#000+
   '10059_U_Skipping re-resolving unit $1, still loading used units'#000+
+  '10060_U_Unloading resource unit $1 (not needed) '#000+
   '11000_O_$1 [options] <inputfile> [options]'#000+
   '11001_W_Only one source file supported'#000+
-  '11002_W_DEF file can be created on','ly for OS/2'#000+
+  '11002_W_DEF file can be creat','ed only for OS/2'#000+
   '11003_E_nested response files are not supported'#000+
   '11004_F_No source file name in command line'#000+
   '11005_N_No option inside $1 config file'#000+
   '11006_E_Illegal parameter: $1'#000+
   '11007_H_-? writes help pages'#000+
-  '11008_F_Too many config files nested'#000,
+  '11008_F_Too many config files ne','sted'#000+
   '11009_F_Unable to open file $1'#000+
   '11010_D_Reading further options from $1'#000+
   '11011_W_Target is already set to: $1'#000+
@@ -798,30 +805,30 @@ const msgtxt : array[0..000192,1..240] of char=(
   #000+
   '11013_F_too many IF(N)DEFs'#000+
   '11014_F_too many ENDIFs'#000+
-  '11015_F_op','en conditional at the end of the file'#000+
+  '11015','_F_open conditional at the end of the file'#000+
   '11016_W_Debug information generation is not supported by this executab'+
   'le'#000+
   '11017_H_Try recompiling with -dGDB'#000+
   '11018_W_You are using the obsolete switch $1'#000+
-  '11019_W_You are using the obsolete switch $1, ple','ase use $2'#000+
+  '11019_W_You are using the obsolete switch $1',', please use $2'#000+
   '11020_N_Switching assembler to default source writing assembler'#000+
   '11021_W_Assembler output selected "$1" is not compatible with "$2"'#000+
   '11022_W_"$1" assembler use forced'#000+
   '11026_T_Reading options from file $1'#000+
-  '11027_T_Reading options fro','m environment $1'#000+
+  '11027_T_Reading option','s from environment $1'#000+
   '11028_D_Handling option "$1"'#000+
   '11029__*** press enter ***'#000+
   '11030_H_Start of reading config file $1'#000+
   '11031_H_End of reading config file $1'#000+
   '11032_D_interpreting option "$1"'#000+
   '11036_D_interpreting firstpass option "$1"'#000+
-  '11033_D_inter','preting file option "$1"'#000+
+  '11033_D_','interpreting file option "$1"'#000+
   '11034_D_Reading config file "$1"'#000+
   '11035_D_found source file name "$1"'#000+
   '11039_E_Unknown code page'#000+
   '11040_F_Config file $1 is a directory'#000+
   '11041_W_Assembler output selected "$1" cannot generate debug info, deb'+
-  'ugging disab','led'#000+
+  'ugging ','disabled'#000+
   '11023_Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPC'+
   'CPU'#010+
   'Copyright (c) 1993-2007 by Florian Klaempfl'#000+
@@ -830,7 +837,7 @@ const msgtxt : array[0..000192,1..240] of char=(
   'Compiler Date      : $FPCDATE'#010+
   'Compiler CPU Target: $FPCCPU'#010+
   #010+
-  'Supported ','targets:'#010+
+  'Suppo','rted targets:'#010+
   '  $OSTARGETS'#010+
   #010+
   'Supported CPU instruction sets:'#010+
@@ -843,37 +850,37 @@ const msgtxt : array[0..000192,1..240] of char=(
   '  $OPTIMIZATIONS'#010+
   #010+
   'This program comes under the GNU General Public Licence'#010+
-  'For more in','formation read COPYING.FPC'#010+
+  'For mo','re information read COPYING.FPC'#010+
   #010+
   'Report bugs,suggestions etc to:'#010+
   '                 [email protected]'#000+
   '11025_**0*_Put + after a boolean switch option to enable it, - to disa'+
   'ble it'#010+
-  '**1a_The compiler doesn'#039't delete the generated assembler file'#010+
-  '**2a','l_List sourcecode lines in assembler file'#010+
+  '**1a_The compiler doesn'#039't delete the generated assembler file',#010+
+  '**2al_List sourcecode lines in assembler file'#010+
   '**2an_List node info in assembler file'#010+
   '*L2ap_Use pipes instead of creating temporary assembler files'#010+
   '**2ar_List register allocation/release info in assembler file'#010+
-  '**2at_List temp allocation/release ','info in assembler file'#010+
+  '**2at_List temp allocation/rel','ease info in assembler file'#010+
   '**1A<x>_Output format:'#010+
   '**2Adefault_Use default assembler'#010+
   '3*2Aas_Assemble using GNU AS'#010+
   '3*2Anasmcoff_COFF (Go32v2) file using Nasm'#010+
   '3*2Anasmelf_ELF32 (Linux) file using Nasm'#010+
-  '3*2Anasmwin32_Win32 object file using Nasm'#010+
-  '3*2','Anasmwdosx_Win32/WDOSX object file using Nasm'#010+
+  '3*2Anasmwin32_Win32 object file using Nas','m'#010+
+  '3*2Anasmwdosx_Win32/WDOSX object file using Nasm'#010+
   '3*2Awasm_Obj file using Wasm (Watcom)'#010+
   '3*2Anasmobj_Obj file using Nasm'#010+
   '3*2Amasm_Obj file using Masm (Microsoft)'#010+
   '3*2Atasm_Obj file using Tasm (Borland)'#010+
-  '3*2Aelf_ELF (Linux) using internal writer'#010+
-  '3*','2Acoff_COFF (Go32v2) using internal writer'#010+
+  '3*2Aelf_ELF (Linux) using internal writ','er'#010+
+  '3*2Acoff_COFF (Go32v2) using internal writer'#010+
   '3*2Apecoff_PE-COFF (Win32) using internal writer'#010+
   '4*2Aas_Assemble using GNU AS'#010+
   '6*2Aas_Unix o-file using GNU AS'#010+
   '6*2Agas_GNU Motorola assembler'#010+
   '6*2Amit_MIT Syntax (old GAS)'#010+
-  '6*2Amot_Standard Motorola a','ssembler'#010+
+  '6*2Amot_Standard Motor','ola assembler'#010+
   'A*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
   'S*2Aas_Assemble using GNU AS'#010+
@@ -881,26 +888,26 @@ const msgtxt : array[0..000192,1..240] of char=(
   '**2bl_Generate local symbol info'#010+
   '**1B_Build all modules'#010+
   '**1C<x>_Code generation options:'#010+
-  '**2Cc<x>_Set default calling',' convention to <x>'#010+
+  '**2Cc<x>_Set default ca','lling convention to <x>'#010+
   '**2CD_Create also dynamic library (not supported)'#010+
   '**2Ce_Compilation with emulated floating point opcodes'#010+
   '**2Cf<x>_Select fpu instruction set to use, see fpc -i for possible va'+
   'lues'#010+
-  '**2CF<x>_Minimal floating point constant ','precision (default, 32, 64)'+
+  '**2CF<x>_Minimal floating point cons','tant precision (default, 32, 64)'+
   #010+
   '**2Cg_Generate PIC code'#010+
   '**2Ch<n>_<n> bytes heap (between 1023 and 67107840)'#010+
   '**2Ci_IO-checking'#010+
   '**2Cn_Omit linking stage'#010+
   '**2Co_Check overflow of integer operations'#010+
-  '**2CO_Check for possible overflow of integer opera','tions'#010+
+  '**2CO_Check for possible overflow of integer ','operations'#010+
   '**2Cp<x>_Select instruction set, see fpc -i for possible values'#010+
   '**2CP<x>=<y>_ packing settings'#010+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   'and 8'#010+
   '**2Cr_Range checking'#010+
-  '**2CR_Verify object method call validity'#010+
-  '*','*2Cs<n>_Set stack size to <n>'#010+
+  '**2CR_Verify object method call valid','ity'#010+
+  '**2Cs<n>_Set stack size to <n>'#010+
   '**2Ct_Stack checking'#010+
   '**2CX_Create also smartlinked library'#010+
   '**1d<x>_Defines the symbol <x>'#010+
@@ -908,41 +915,41 @@ const msgtxt : array[0..000192,1..240] of char=(
   '**2Dd<x>_Set description to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '*O2Dw_PM application'#010+
-  '**1e<x>_Se','t path to executable'#010+
+  '**1e<','x>_Set path to executable'#010+
   '**1E_Same as -Cn'#010+
   '**1fPIC_Same as -Cg'#010+
   '**1F<x>_Set file names and paths:'#010+
   '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
   'sed'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
-  '**2FC<x>_Set RC compiler binary name to',' <x>'#010+
+  '**2FC<x>_Set RC compiler binary na','me to <x>'#010+
   '**2FD<x>_Set the directory where to search for compiler utilities'#010+
   '**2Fe<x>_Redirect error output to <x>'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#010+
   '**2Fi<x>_Add <x> to include path'#010+
-  '**2Fl<x>','_Add <x> to library path'#010+
+  '**2','Fl<x>_Add <x> to library path'#010+
   '**2FL<x>_Use <x> as dynamic linker'#010+
   '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
   'r'#010+
   '**2Fo<x>_Add <x> to object path'#010+
   '**2Fr<x>_Load error message file <x>'#010+
-  '**2FR<x>_Set resource (.res) linker to ','<x>'#010+
+  '**2FR<x>_Set resource (.res) linke','r to <x>'#010+
   '**2Fu<x>_Add <x> to unit path'#010+
   '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
   '*g1g_Generate debug information (default format for target)'#010+
   '*g2gc_Generate checks for pointers'#010+
-  '*g2gh_Use heaptrace unit (for memory leak/corruption debugg','ing)'#010+
+  '*g2gh_Use heaptrace unit (for memory leak/corruption d','ebugging)'#010+
   '*g2gl_Use line info unit (show more info with backtraces)'#010+
   '*g2go<x>_Set debug information options'#010+
   '*g3godwarfsets_ Enable Dwarf set debug information (breaks gdb < 6.5)'#010+
   '*g2gp_Preserve case in stabs symbol names'#010+
-  '*g2gs_Generate stabs debug',' information'#010+
+  '*g2gs_Generate stabs ','debug information'#010+
   '*g2gt_Trash local variables (to detect uninitialized uses)'#010+
   '*g2gv_Generates programs traceable with valgrind'#010+
   '*g2gw_Generate dwarf-2 debug information (same as -gw2)'#010+
   '*g2gw2_Generate dwarf-2 debug information'#010+
-  '*g2gw3_Generate dwarf','-3 debug information'#010+
+  '*g2gw3_Generate ','dwarf-3 debug information'#010+
   '**1i_Information'#010+
   '**2iD_Return compiler date'#010+
   '**2iV_Return short compiler version'#010+
@@ -950,67 +957,67 @@ const msgtxt : array[0..000192,1..240] of char=(
   '**2iSO_Return compiler OS'#010+
   '**2iSP_Return compiler host processor'#010+
   '**2iTO_Return target OS'#010+
-  '**2iTP_Return ta','rget processor'#010+
+  '**2iTP_Retu','rn target processor'#010+
   '**1I<x>_Add <x> to include path'#010+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1l_Write logo'#010+
   '**1M<x>_Set language mode to <x>'#010+
   '**2Mfpc_Free Pascal dialect (default)'#010+
   '**2Mobjfpc_FPC mode with Object Pascal support'#010+
-  '**2Mdelphi_Delphi 7 compatib','ility mode'#010+
+  '**2Mdelphi_Delphi 7 com','patibility mode'#010+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
   '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
   '**1n_Do not read the default config files'#010+
   '**1N<x>_Node tree optimizations'#010+
   '**2Nu_Unroll loops'#010+
-  '**1o<x>_Change the name of the executable pr','oduced to <x>'#010+
+  '**1o<x>_Change the name of the executab','le produced to <x>'#010+
   '**1O<x>_Optimizations:'#010+
   '**2O-_Disable optimizations'#010+
   '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
   '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
   '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
-  '**2Oa<','x>=<y>_Set alignment'#010+
+  '*','*2Oa<x>=<y>_Set alignment'#010+
   '**2Oo[NO]<x>_Enable or disable optimizations, see fpc -i for possible '+
   'values'#010+
   '**2Op<x>_Set target cpu for optimizing, see fpc -i for possible values'+
   #010+
   '**2Os_Optimize for size rather than speed'#010+
-  '**1pg_Generate profile code f','or gprof (defines FPC_PROFILE)'#010+
+  '**1pg_Generate profile c','ode for gprof (defines FPC_PROFILE)'#010+
   '**1R<x>_Assembler reading style:'#010+
   '**2Rdefault_Use default assembler for target'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
   '3*2Rintel_Read Intel style assembler'#010+
   '6*2RMOT_Read motorola style assembler'#010+
-  '**1S<x>_Syntax options',':'#010+
+  '**1S<x>_Syntax op','tions:'#010+
   '**2S2_Same as -Mobjfpc'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sa_Turn on assertions'#010+
   '**2Sd_Same as -Mdelphi'#010+
   '**2Se<x>_Error options. <x> is a combination of the following:'#010+
-  '**3*_<n> : Compiler halts after the <n> errors (default',' is 1)'#010+
+  '**3*_<n> : Compiler halts after the <n> errors (de','fault is 1)'#010+
   '**3*_w : Compiler also halts after warnings'#010+
   '**3*_n : Compiler also halts after notes'#010+
   '**3*_h : Compiler also halts after hints'#010+
   '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
-  '**2Sh_Use ansistrings by default instead of shor','tstrings'#010+
+  '**2Sh_Use ansistrings by default instead of',' shortstrings'#010+
   '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
   '**2Sk_Load fpcylix unit'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**3SIcom_COM compatible interface (default)'#010+
   '**3SIcorba_CORBA compatible interface'#010+
-  '**2Sm_Support macros ','like C (global)'#010+
+  '**2Sm_Support ma','cros like C (global)'#010+
   '**2So_Same as -Mtp'#010+
   '**2Ss_Constructor name must be init (destructor must be done)'#010+
   '**2St_Allow static keyword in objects'#010+
   '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
-  '**1s_Do not call assembler and linker'#010+
-  '**','2sh_Generate script to link on host'#010+
+  '**1s_Do not call assembler and link','er'#010+
+  '**2sh_Generate script to link on host'#010+
   '**2st_Generate script to link on target'#010+
   '**2sr_Skip register allocation phase (use with -alr)'#010+
   '**1T<x>_Target operating system:'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
   '3*2Tfreebsd_FreeBSD'#010+
-  '3*2Tgo32','v2_Version 2 of DJ Delorie DOS extender'#010+
+  '3*2','Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tnetbsd_NetBSD'#010+
   '3*2Tnetware_Novell Netware Module (clib)'#010+
@@ -1018,7 +1025,7 @@ const msgtxt : array[0..000192,1..240] of char=(
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Tos2_OS/2 / eComStation'#010+
   '3*2Tsunos_SunOS/Solaris'#010+
-  '3*2Tsymbian_','Symbian OS'#010+
+  '3*2Tsym','bian_Symbian OS'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
   '3*2Twin32_Windows 32 Bit'#010+
@@ -1027,7 +1034,7 @@ const msgtxt : array[0..000192,1..240] of char=(
   '6*2Tamiga_Commodore Amiga'#010+
   '6*2Tatari_Atari ST/STe/TT'#010+
   '6*2Tlinux_Linux/m68k'#010+
-  '6*2Tmacos_Macintosh m68','k (not supported)'#010+
+  '6*2Tmacos_Macintos','h m68k (not supported)'#010+
   '6*2Tpalmos_PalmOS'#010+
   'A*2Tlinux_Linux'#010+
   'A*2Twince_Windows CE'#010+
@@ -1036,68 +1043,74 @@ const msgtxt : array[0..000192,1..240] of char=(
   'P*2Tlinux_Linux on PowerPC'#010+
   'P*2Tmacos_Mac OS (classic) on PowerPC'#010+
   'P*2Tmorphos_MorphOS'#010+
-  'S*2Tlinux_L','inux'#010+
+  'S*2Tli','nux_Linux'#010+
   '**1u<x>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#010+
   '**2Un_Do not check where the unit name matches the file name'#010+
   '**2Ur_Generate release unit files (never automatically recompiled)'#010+
   '**2Us_Compile a system unit'#010+
-  '**1v<x>_Be verbose. <x> is ','a combination of the following letters:'#010+
+  '**1v<x>_Be verbose. <x','> is a combination of the following letters:'#010+
   '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
   '**2*_w : Show warnings               u : Show unit info'#010+
   '**2*_n : Show notes                  t : Show tried/used files'#010+
-  '**2*_h : Sh','ow hints                  c : Show conditionals'#010+
+  '**2*_h',' : Show hints                  c : Show conditionals'#010+
   '**2*_i : Show general info           d : Show debug info'#010+
   '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
-  '**2*_a : Show everything             x : Executable info (Win32 o','nly'+
+  '**2*_a : Show everything             x : Executable info (Wi','n32 only'+
   ')'#010+
   '**2*_b : Write file names messages with full path'#010+
   '**2*_v : Write fpcdebug.txt with     p : Write tree.log with parse tre'+
   'e'#010+
   '**2*_    lots of debugging info'#010+
   '3*1W<x>_Target-specific options (targets)'#010+
-  'A*1W<x>_Target-specific options (target','s)'#010+
+  'A*1W<x>_Target-specific options (t','argets)'#010+
   'P*1W<x>_Target-specific options (targets)'#010+
   '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  '3*2WB_Create a relocatable image (Windo','ws)'#010+
+  '3*2WB_Create a relocatable image (','Windows)'#010+
   'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
   '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
   'A*2WC_Specify console type application (Windows)'#010+
   'P*2WC_Specify console type application (Classic Mac OS)'#010+
-  '3*2WD_Use DEFFILE t','o export functions of DLL or EXE (Windows)'#010+
+  '3*2WD_Use DEFF','ILE to export functions of DLL or EXE (Windows)'#010+
   'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
-  '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
+  '3*2We_Use external resources (Darwin)'#010+
+  'P*2We_Use external resources (Darwin)'#010+
+  'p*2We_Use external resources (Darwin)'#010+
+  '3*2WF_Specify fu','ll-screen type application (EMX, OS/2)'#010+
   '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
-  'A*2WG_Specify graphi','c type application (Windows)'#010+
+  'A*2WG_Specify graphic type application (Windows)'#010+
   'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
+  '3*2Wi_Use internal resources (Darwin',')'#010+
+  'P*2Wi_Use internal resources (Darwin)'#010+
+  'p*2Wi_Use internal resources (Darwin)'#010+
   '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  '3*2WR_Generate ','relocation code (Windows)'#010+
+  '3*2WR_Generate relocat','ion code (Windows)'#010+
   'A*2WR_Generate relocation code (Windows)'#010+
   'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
   '**1X_Executable options:'#010+
   '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
   'ux)'#010+
-  '**2Xd_Do not use ','standard library search path (needed for cross comp'+
+  '**2Xd_Do not use standar','d library search path (needed for cross comp'+
   'ile)'#010+
   '**2Xe_Use external linker'#010+
   '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
   'to executable'#010+
   '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
-  '**2Xi_','Use internal linker'#010+
+  '**2Xi_Use int','ernal linker'#010+
   '**2Xm_Generate link map'#010+
   '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
   's '#039'main'#039')'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
-  '**2Xr<x>_Set library search path to <x> (needed for cross compile) (','B'+
-  'eOS, Linux)'#010+
+  '**2Xr<x>_Set library search path to <x> (needed for cross compile) (Be'+
+  'OS, L','inux)'#010+
   '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
   ', Linux, Mac OS, Solaris)'#010+
   '**2Xs_Strip all symbols from executable'#010+
   '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
-  '**2Xt_Link with stati','c libraries (-static is passed to linker)'#010+
+  '**2Xt_Link with static libra','ries (-static is passed to linker)'#010+
   '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
   '**1?_Show this help'#010+

+ 32 - 3
compiler/options.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Florian Klaempfl and Peter Vreman
+    Copyright (c) 1998-2008 by Florian Klaempfl and Peter Vreman
 
     Reads command line options and config files
 
@@ -76,7 +76,8 @@ uses
   version,
   cutils,cmsgs,
   comphook,
-  symtable,scanner,rabase
+  symtable,scanner,rabase,
+  i_bsd
   ;
 
 const
@@ -1318,6 +1319,17 @@ begin
                         UseDeffileForExports:=not UnsetBool(More, j);
                         UseDeffileForExportsSetExplicitly:=true;
                       end;
+                    'e':
+                      begin
+                        if (target_info.system in systems_darwin) then
+                          begin
+                            RegisterRes(res_macosx_ext_info,TWinLikeResourceFile);
+                            set_target_res(res_ext);
+                            target_info.resobjext:='.fpcres';
+                          end
+                        else
+                          IllegalPara(opt);
+                      end;
                     'F':
                       begin
                         if UnsetBool(More, j) then
@@ -1337,6 +1349,17 @@ begin
                         GenerateImportSection:=not UnsetBool(More,j);
                         GenerateImportSectionSetExplicitly:=true;
                       end;
+                    'i':
+                      begin
+                        if (target_info.system in systems_darwin) then
+                          begin
+                            set_target_res(res_macho);
+                            target_info.resobjext:=
+                              targetinfos[target_info.system]^.resobjext;
+                          end
+                        else
+                          IllegalPara(opt);
+                      end;
                     'N':
                       begin
                         RelocSection:=UnsetBool(More,j);
@@ -1996,6 +2019,13 @@ begin
     include(init_settings.moduleswitches,cs_create_pic)
   else
     exclude(init_settings.moduleswitches,cs_create_pic);
+    
+  { Resources support }
+  if (tf_has_winlike_resources in target_info.flags) then
+    if def then
+      def_system_macro('FPC_HAS_WINLIKERESOURCES')
+    else
+      undef_system_macro('FPC_HAS_WINLIKERESOURCES');
 end;
 
 
@@ -2186,7 +2216,6 @@ begin
   def_system_macro('FPC_HAS_TYPE_EXTENDED');
   def_system_macro('FPC_HAS_TYPE_DOUBLE');
   def_system_macro('FPC_HAS_TYPE_SINGLE');
-  def_system_macro('FPC_HAS_RESOURCES');
 {$endif}
 {$ifdef m68k}
   def_system_macro('CPU68');

+ 9 - 0
compiler/parser.pas

@@ -68,6 +68,8 @@ implementation
          loaded_units:=TLinkedList.Create;
 
          usedunits:=TLinkedList.Create;
+         
+         unloaded_units:=TLinkedList.Create;
 
          { global switches }
          current_settings.globalswitches:=init_settings.globalswitches;
@@ -149,6 +151,11 @@ implementation
              usedunits.free;
              usedunits:=nil;
            end;
+         if assigned(unloaded_units) then
+           begin
+             unloaded_units.free;
+             unloaded_units:=nil;
+           end;
 
          { if there was an error in the scanner, the scanner is
            still assinged }
@@ -492,6 +499,8 @@ implementation
                    end;
                  hp:=hp2;
                end;
+              { free also unneeded units we didn't free before }
+              unloaded_units.Clear;
              end;
            dec(compile_level);
            set_current_module(olddata^.old_current_module);

+ 106 - 32
compiler/pmodules.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Florian Klaempfl
+    Copyright (c) 1998-2008 by Florian Klaempfl
 
     Handles the parsing and loading of the modules (ppufiles)
 
@@ -226,47 +226,49 @@ implementation
       end;
 
 
-    Procedure InsertResourceInfo;
-
+    Function CheckResourcesUsed : boolean;
     var
       hp           : tused_unit;
       found        : Boolean;
+    begin
+      CheckResourcesUsed:=tf_has_winlike_resources in target_info.flags;
+      if not CheckResourcesUsed then exit;
+
+      hp:=tused_unit(usedunits.first);
+      found:=((current_module.flags and uf_has_resourcefiles)=uf_has_resourcefiles);
+      If not found then
+        While Assigned(hp) and not found do
+          begin
+          Found:=((hp.u.flags and uf_has_resourcefiles)=uf_has_resourcefiles);
+          hp:=tused_unit(hp.next);
+          end;
+      CheckResourcesUsed:=found;
+    end;
+
+    Procedure InsertResourceInfo(ResourcesUsed : boolean);
+
+    var
       I            : Integer;
       ResourceInfo : TAsmList;
 
     begin
-      if target_res.id=res_elf then
+      if (target_res.id in [res_elf,res_macho]) then
         begin
-        hp:=tused_unit(usedunits.first);
-        found:=false;
-        Found:=((current_module.flags and uf_has_resourcefiles)=uf_has_resourcefiles);
-        If not found then
-          While Assigned(hp) and not Found do
-            begin
-            Found:=((hp.u.flags and uf_has_resourcefiles)=uf_has_resourcefiles);
-            hp:=tused_unit(hp.next);
-            end;
         ResourceInfo:=TAsmList.Create;
-        if found then
-          begin
+
+        maybe_new_object_file(ResourceInfo);
+        new_section(ResourceInfo,sec_data,'FPC_RESLOCATION',sizeof(aint));
+        ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
+        if ResourcesUsed then
           { Valid pointer to resource information }
-          ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
-          ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0));
-{$ifdef EXTERNALRESPTRS}
-          current_module.linkotherofiles.add('resptrs.o',link_always);
-{$else EXTERNALRESPTRS}
-          new_section(ResourceInfo,sec_fpc,'resptrs',4);
-          ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESSYMBOL',AT_DATA,0));
-          For I:=1 to 32 do
-            ResourceInfo.Concat(Tai_const.Create_32bit(0));
-{$endif EXTERNALRESPTRS}
-          end
+          ResourceInfo.concat(Tai_const.Createname('FPC_RESSYMBOL',0))
         else
-          begin
           { Nil pointer to resource information }
-          ResourceInfo.concat(Tai_symbol.Createname_global('FPC_RESLOCATION',AT_DATA,0));
+          {$IFDEF CPU32}
           ResourceInfo.Concat(Tai_const.Create_32bit(0));
-          end;
+          {$ELSE}
+          ResourceInfo.Concat(Tai_const.Create_64bit(0));
+          {$ENDIF}
         maybe_new_object_file(current_asmdata.asmlists[al_globals]);
         current_asmdata.asmlists[al_globals].concatlist(ResourceInfo);
         ResourceInfo.free;
@@ -450,6 +452,58 @@ implementation
       end;
 
 
+    function MaybeRemoveResUnit : boolean;
+      var
+        resources_used : boolean;
+        hp : tmodule;
+        uu : tused_unit;
+        unitname : shortstring;
+      begin
+        { We simply remove the unit from:
+           - usedunit list, so that things like init/finalization table won't
+              contain references to this unit
+           - loaded_units list, so that the unit object file doesn't get linked
+             with the executable. }
+        { Note: on windows we always need resources! }
+        resources_used:=(target_info.system in system_all_windows)
+                         or CheckResourcesUsed;
+        if (not resources_used) and (tf_has_winlike_resources in target_info.flags) then
+          begin
+            { resources aren't used, so we don't need this unit }
+            if target_res.id=res_ext then
+              unitname:='FPEXTRES'
+            else
+              unitname:='FPINTRES';
+            Message1(unit_u_unload_resunit,unitname);
+            { find the module }
+            hp:=tmodule(loaded_units.first);
+            while assigned(hp) do
+              begin
+                if hp.is_unit and (hp.modulename^=unitname) then break;
+                hp:=tmodule(hp.next);
+              end;
+            if not assigned(hp) then
+              internalerror(200801071);
+            { find its tused_unit in the global list }
+            uu:=tused_unit(usedunits.first);
+            while assigned(uu) do
+              begin
+                if uu.u=hp then break;
+                uu:=tused_unit(uu.next);
+              end;
+            if not assigned(uu) then
+              internalerror(200801072);
+           { remove the tused_unit }
+            usedunits.Remove(uu);
+            uu.Free;
+           { remove the module }
+            loaded_units.Remove(hp);
+            unloaded_units.Concat(hp);
+          end;
+        MaybeRemoveResUnit:=resources_used;
+      end;
+
+
     procedure loaddefaultunits;
       begin
         { we are going to rebuild the symtablestack, clear it first }
@@ -507,6 +561,14 @@ implementation
              AddUnit('softfpu');
            }
 {$endif cpufpemu}
+           { Which kind of resource support?
+             Note: if resources aren't used this unit will be removed later,
+             otherwise we need it here since it must be loaded quite early }
+           if (tf_has_winlike_resources in target_info.flags) then
+             if target_res.id=res_ext then
+               AddUnit('fpextres')
+             else
+               AddUnit('fpintres');
          end;
         { Objpas unit? }
         if m_objpas in current_settings.modeswitches then
@@ -1769,6 +1831,7 @@ implementation
          init_procinfo,
          main_procinfo : tcgprocinfo;
          force_init_final : boolean;
+         resources_used : boolean;
       begin
          DLLsource:=islibrary;
          Status.IsLibrary:=IsLibrary;
@@ -1778,6 +1841,7 @@ implementation
          main_procinfo:=nil;
          init_procinfo:=nil;
          finalize_procinfo:=nil;
+         resources_used:=false;
 
          { DLL defaults to create reloc info }
          if islibrary then
@@ -1983,7 +2047,7 @@ implementation
              exit;
            end;
 
-         { remove all unused units, this happends when units are removed
+         { remove all unused units, this happens when units are removed
            from the uses clause in the source and the ppu was already being loaded }
          hp:=tmodule(loaded_units.first);
          while assigned(hp) do
@@ -1992,12 +2056,19 @@ implementation
             hp:=tmodule(hp.next);
             if hp2.is_unit and
                not assigned(hp2.globalsymtable) then
-              loaded_units.remove(hp2);
+                begin
+                  loaded_units.remove(hp2);
+                  unloaded_units.concat(hp2);
+                end;
           end;
 
          { do we need to add the variants unit? }
          maybeloadvariantsunit;
 
+         { Now that everything has been compiled we know if we need resource
+           support. If not, remove the unit. }
+         resources_used:=MaybeRemoveResUnit;
+
          linker.initsysinitunitname;
          if target_info.system in system_internal_sysinit then
          begin
@@ -2048,7 +2119,7 @@ implementation
          insertmemorysizes;
 
          { Insert symbol to resource info }
-         InsertResourceInfo;
+         InsertResourceInfo(resources_used);
 
          { create dwarf debuginfo }
          create_dwarf;
@@ -2101,6 +2172,9 @@ implementation
                       end;
                     hp:=hp2;
                   end;
+                 { free also unneeded units we didn't free before }
+                 if not needsymbolinfo then
+                   unloaded_units.Clear;
                  { finally we can create a executable }
                  if DLLSource then
                    linker.MakeSharedLibrary

+ 27 - 0
compiler/powerpc64/cgcpu.pas

@@ -726,6 +726,33 @@ begin
   ref2 := ref;
   fixref(list, ref2);
 
+  { unaligned 64 bit accesses are much slower than unaligned }
+  { 32 bit accesses because they cause a hardware exception  }
+  { (which isn't handled by linux, so there you even get a   }
+  {  crash)                                                  }
+  if (ref.alignment<>0) and
+     (fromsize in [OS_64,OS_S64]) and
+     (ref.alignment<4) then
+    begin
+      if (ref2.base<>NR_NO) and
+         (ref2.index<>NR_NO) then
+        begin
+	  // althoug fixref above makes sure that the location ref points to can be
+	  // accessed using the existing opcode restrictions, ref+4 still may be too
+	  // large to encode
+          tmpreg:=getintregister(list,OS_64);
+          a_op_reg_reg_reg(list,OP_ADD,OS_64,ref2.base,ref2.index,tmpreg);
+          ref2.base:=tmpreg;
+          ref2.index:=NR_NO;
+        end;
+      tmpreg:=getintregister(list,OS_32);
+      a_load_ref_reg(list,OS_32,OS_32,ref2,tmpreg);
+      inc(ref2.offset,4);
+      a_load_ref_reg(list,OS_32,OS_32,ref2,reg); 
+      list.concat(taicpu.op_reg_reg_const_const(A_RLDIMI, reg, tmpreg, 32, 0));
+      exit;
+    end;
+
   op := loadinstr[fromsize, ref2.index <> NR_NO, false];
   { there is no LWAU instruction, simulate using ADDI and LWA }
   if (op = A_NOP) then begin

+ 59 - 0
compiler/rescmn.pas

@@ -0,0 +1,59 @@
+{
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Common resource target infos
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit rescmn;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  Systems;
+
+    const
+       res_elf_info : tresinfo =
+          (
+             id     : res_elf;
+             resbin : 'fpcres';
+             rescmd : '-o $OBJ -a $ARCH -of elf $DBG';
+             { cross compiled windres can be used to compile .rc files on linux }
+             rcbin  : 'windres';
+             rccmd  : '--include $INC -O res -o $RES $RC';
+             resourcefileclass : nil;
+             resflags : [];
+          );
+
+       res_ext_info : tresinfo =
+          (
+             id     : res_ext;
+             resbin : 'fpcres';
+             rescmd : '-o $OBJ -a $ENDIAN -of external $DBG';
+             rcbin  : 'windres';
+             rccmd  : '--include $INC -O res -o $RES $RC';
+             resourcefileclass : nil;
+             resflags : [res_external_file];
+          );
+
+
+implementation
+
+end.

+ 1 - 1
compiler/scandir.pas

@@ -1000,7 +1000,7 @@ implementation
         if target_info.res<>res_none then
           begin
           current_module.flags:=current_module.flags or uf_has_resourcefiles;
-          if (target_info.res = res_emxbind) and
+          if (res_single_file in target_res.resflags) and
                                  not (Current_module.ResourceFiles.Empty) then
             Message(scan_w_only_one_resourcefile_supported)
           else

+ 17 - 13
compiler/systems.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Florian Klaempfl
+    Copyright (c) 1998-2008 by Florian Klaempfl
 
     This unit contains information about the target systems supported
     (these are not processor specific)
@@ -183,12 +183,14 @@ interface
        );
 
        tres = (res_none
-            ,res_gnu_windres,res_emxbind
+            ,res_gnu_windres,res_watcom_wrc_os2
             ,res_m68k_palmos,res_m68k_mpw
             ,res_powerpc_mpw,res_elf
-            ,res_gnu_wince_windres
-            ,res_win64_gorc
+            ,res_win64_gorc, res_macho, res_ext
        );
+       
+       tresinfoflags = (res_external_file,res_arch_in_file_name
+            ,res_single_file);
 
        tdbg = (dbg_none
             ,dbg_stabs,dbg_dwarf2,dbg_dwarf3
@@ -276,13 +278,14 @@ interface
        tresinfo = record
           id      : tres;
           { Compiler for resource (.rc or .res) to obj }
-          resbin  : string[8];
+          resbin  : string[10];
           rescmd  : string[50];
           { Optional compiler for resource script (.rc) to binary resource (.res). }
           { If it is not provided resbin and rescmd will be used.                 }
-          rcbin   : string[8];
+          rcbin   : string[10];
           rccmd   : string[50];
           resourcefileclass : TAbstractResourceFileClass;
+          resflags : set of tresinfoflags;
        end;
 
        pdbginfo = ^tdbginfo;
@@ -318,7 +321,8 @@ interface
             tf_no_pic_supported,
             tf_pic_default,
             { the os does some kind of stack checking and it can be converted into a rte 202 }
-            tf_no_generic_stackcheck
+            tf_no_generic_stackcheck,
+            tf_has_winlike_resources
        );
 
        psysteminfo = ^tsysteminfo;
@@ -339,8 +343,8 @@ interface
           unitlibext,
           asmext,
           objext,
-          resext,
-          resobjext    : string[4];
+          resext       : string[4];
+          resobjext    : string[7];
           sharedlibext : string[10];
           staticlibext,
           staticlibprefix : string[4];
@@ -570,7 +574,9 @@ begin
      target_res:=resinfos[t]^;
      result:=true;
      exit;
-   end;
+   end
+  else
+   FillByte(target_res,sizeof(target_res),0);
 end;
 
 
@@ -699,9 +705,7 @@ var
   t : tres;
 begin
   t:=r.id;
-  if assigned(resinfos[t]) then
-    writeln('Warning: resourcecompiler is already registered!')
-  else
+  if not assigned(resinfos[t]) then
     Getmem(resinfos[t],sizeof(tresinfo));
   resinfos[t]^:=r;
   resinfos[t]^.resourcefileclass:=rcf;

+ 43 - 22
compiler/systems/i_bsd.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Peter Vreman
+    Copyright (c) 1998-2008 by Peter Vreman
 
     This unit implements support information structures for FreeBSD/NetBSD
 
@@ -27,9 +27,30 @@ unit i_bsd;
   interface
 
     uses
-       systems;
+       systems, rescmn;
 
     const
+       res_macho_info : tresinfo =
+           (
+             id     : res_macho;
+             resbin : 'fpcres';
+             rescmd : '-o $OBJ -a $ARCH -of mach-o $DBG';
+             rcbin  : 'windres';
+             rccmd  : '--include $INC -O res -o $RES $RC';
+             resourcefileclass : nil;
+             resflags : [];
+           );
+       res_macosx_ext_info : tresinfo =
+          (
+             id     : res_ext;
+             resbin : 'fpcres';
+             rescmd : '-o $OBJ -a $ENDIAN -of external $DBG';
+             rcbin  : 'windres';
+             rccmd  : '--include $INC -O res -o $RES $RC';
+             resourcefileclass : nil;
+             resflags : [res_external_file,res_arch_in_file_name];
+          );
+
        system_i386_freebsd_info : tsysteminfo =
           (
             system       : system_i386_FreeBSD;
@@ -39,7 +60,7 @@ unit i_bsd;
             {$ifdef segment_threadvars}
                                         tf_section_threadvars,
             {$endif segment_threadvars}
-                           tf_needs_symbol_type,tf_needs_symbol_size,tf_smartlink_library {,tf_smartlink_sections}];
+                           tf_needs_symbol_type,tf_needs_symbol_size,tf_smartlink_library {,tf_smartlink_sections},tf_has_winlike_resources];
             cpu          : cpu_i386;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -69,7 +90,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -101,7 +122,7 @@ unit i_bsd;
             shortname    : 'FreeBSD';
             flags        : [tf_needs_symbol_size,tf_needs_dwarf_cfi,{Linux: tf_library_needs_pic,}tf_needs_symbol_type,
                             tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library
-                                {	tf_pic_uses_got,tf_smartlink_sections}];
+                                {	tf_pic_uses_got,tf_smartlink_sections},tf_has_winlike_resources];
             cpu          : cpu_x86_64;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;HASUNIX;BSD';
@@ -131,7 +152,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_dwarf2;            //dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -161,7 +182,7 @@ unit i_bsd;
             system       : system_i386_NetBSD;
             name         : 'NetBSD for i386';
             shortname    : 'NetBSD';
-            flags        : [tf_under_development,tf_files_case_sensitive,tf_smartlink_library,tf_use_function_relative_addresses];
+            flags        : [tf_under_development,tf_files_case_sensitive,tf_smartlink_library,tf_use_function_relative_addresses,tf_has_winlike_resources];
             cpu          : cpu_i386;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -191,7 +212,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -220,7 +241,7 @@ unit i_bsd;
             system       : system_i386_OpenBSD;
             name         : 'OpenBSD for i386';
             shortname    : 'OpenBSD';
-            flags        : [tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library];
+            flags        : [tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_i386;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -250,7 +271,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -279,7 +300,7 @@ unit i_bsd;
             system       : system_m68k_NetBSD;
             name         : 'NetBSD for m68k';
             shortname    : 'NetBSD';
-            flags        : [tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library];
+            flags        : [tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_m68k;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -309,7 +330,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_big;
@@ -338,7 +359,7 @@ unit i_bsd;
             system       : system_powerpc_netbsd;
             name         : 'NetBSD for PowerPC';
             shortname    : 'NetBSD';
-            flags        : [tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library];
+            flags        : [tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_powerpc;
             unit_env     : '';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -368,7 +389,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_big;
@@ -399,7 +420,7 @@ unit i_bsd;
             system       : system_powerpc_darwin;
             name         : 'Darwin for PowerPC';
             shortname    : 'Darwin';
-            flags        : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_default];
+            flags        : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_default,tf_has_winlike_resources];
             cpu          : cpu_powerpc;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -429,7 +450,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_macho;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_big;
@@ -460,7 +481,7 @@ unit i_bsd;
             system       : system_i386_darwin;
             name         : 'Darwin for i386';
             shortname    : 'Darwin';
-            flags        : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_uses_got,tf_pic_default];
+            flags        : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_uses_got,tf_pic_default,tf_has_winlike_resources];
             cpu          : cpu_i386;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -490,7 +511,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_macho;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -521,7 +542,7 @@ unit i_bsd;
             system       : system_powerpc64_darwin;
             name         : 'Darwin for PowerPC64';
             shortname    : 'Darwin';
-            flags        : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_default];
+            flags        : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_default,tf_has_winlike_resources];
             cpu          : cpu_powerpc64;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -551,7 +572,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_macho;
             dbg          : dbg_dwarf2;
             script       : script_unix;
             endian       : endian_big;
@@ -582,7 +603,7 @@ unit i_bsd;
             system       : system_x86_64_darwin;
             name         : 'Darwin for x86_64';
             shortname    : 'Darwin';
-            flags        : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_default];
+            flags        : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_default,tf_has_winlike_resources];
             cpu          : cpu_x86_64;
             unit_env     : 'BSDUNITS';
             extradefines : 'UNIX;BSD;HASUNIX';
@@ -612,7 +633,7 @@ unit i_bsd;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_macho;
             dbg          : dbg_dwarf2;
             script       : script_unix;
             endian       : endian_little;

+ 9 - 6
compiler/systems/i_emx.pas

@@ -27,12 +27,15 @@ unit i_emx;
        systems;
 
     const
-       res_emxbind_info : tresinfo =
+       res_wrc_os2_info : tresinfo =
           (
-            id     : res_emxbind;
-            resbin : 'emxbind';
-            rescmd : '-b -r $RES $OBJ'
-            (* Not really used - see TLinkerEMX.SetDefaultInfo in t_emx.pas. *)
+             id     : res_watcom_wrc_os2;
+             resbin : '';
+             rescmd : '';
+             rcbin  : 'wrc';
+             rccmd  : '-r -zm -q -bt=os2 -fo=$RES $RC';
+             resourcefileclass : nil;
+             resflags : [res_single_file];
           );
 
        system_i386_emx_info : tsysteminfo =
@@ -70,7 +73,7 @@ unit i_emx;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_emxbind;
+            res          : res_watcom_wrc_os2;
             dbg          : dbg_stabs;
             script       : script_dos;
             endian       : endian_little;

+ 21 - 43
compiler/systems/i_linux.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Peter Vreman
+    Copyright (c) 1998-2008 by Peter Vreman
 
     This unit implements support information structures for linux
 
@@ -24,31 +24,9 @@ unit i_linux;
   interface
 
     uses
-       systems;
+       systems, rescmn;
 
     const
-       res_elf32_info : tresinfo =
-          (
-             id     : res_elf;
-             resbin : 'fpcres';
-             rescmd : '-o $OBJ -i $RES';
-             { cross compiled windres can be used to compile .rc files on linux }
-             rcbin  : 'windres';
-             rccmd  : '--include $INC -O res -o $RES $RC';
-             resourcefileclass : nil;
-          );
-
-       res_elf64_info : tresinfo =
-          (
-             id     : res_elf;
-             resbin : 'fpcres';
-             rescmd : '-o $OBJ -i $RES';
-             { cross compiled windres can be used to compile .rc files on linux }
-             rcbin  : 'windres';
-             rccmd  : '--include $INC -O res -o $RES $RC';
-             resourcefileclass : nil;
-          );
-
        system_i386_linux_info : tsysteminfo =
           (
             system       : system_i386_LINUX;
@@ -59,7 +37,7 @@ unit i_linux;
                             tf_section_threadvars,
 {$endif segment_threadvars}
                             tf_needs_symbol_type,tf_files_case_sensitive,tf_use_function_relative_addresses,
-                            tf_smartlink_library,tf_needs_dwarf_cfi];
+                            tf_smartlink_library,tf_needs_dwarf_cfi,tf_has_winlike_resources];
             cpu          : cpu_i386;
             unit_env     : 'LINUXUNITS';
             extradefines : 'UNIX;HASUNIX';
@@ -118,7 +96,7 @@ unit i_linux;
             system       : system_x86_6432_LINUX;
             name         : 'Linux for x64_6432';
             shortname    : 'Linux6432';
-            flags        : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_pic_uses_got{,tf_smartlink_sections},tf_smartlink_library];
+            flags        : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_pic_uses_got{,tf_smartlink_sections},tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_x86_64;
             unit_env     : 'LINUXUNITS';
             extradefines : 'UNIX;HASUNIX';
@@ -148,7 +126,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -178,7 +156,7 @@ unit i_linux;
             name         : 'Linux for m68k';
             shortname    : 'Linux';
             flags        : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,tf_use_function_relative_addresses,
-                            tf_smartlink_library];
+                            tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_m68k;
             unit_env     : 'LINUXUNITS';
             extradefines : 'UNIX;HASUNIX';
@@ -208,7 +186,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_big;
@@ -238,7 +216,7 @@ unit i_linux;
             name         : 'Linux for PowerPC';
             shortname    : 'Linux';
             flags        : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,tf_use_function_relative_addresses,
-                            tf_smartlink_library];
+                            tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_powerpc;
             unit_env     : '';
             extradefines : 'UNIX;HASUNIX';
@@ -268,7 +246,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_big;
@@ -298,7 +276,7 @@ unit i_linux;
             name         : 'Linux for PowerPC64';
             shortname    : 'Linux';
             flags        : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,tf_use_function_relative_addresses,
-                            tf_requires_proper_alignment,tf_smartlink_library];
+                            tf_requires_proper_alignment,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_powerpc64;
             unit_env     : '';
             extradefines : 'UNIX;HASUNIX';
@@ -328,7 +306,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_dwarf2;
             script       : script_unix;
             endian       : endian_big;
@@ -358,7 +336,7 @@ unit i_linux;
             name         : 'Linux for Alpha';
             shortname    : 'Linux';
             flags        : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,
-                            tf_use_function_relative_addresses,tf_smartlink_library];
+                            tf_use_function_relative_addresses,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_alpha;
             unit_env     : 'LINUXUNITS';
             extradefines : 'UNIX;HASUNIX';
@@ -388,7 +366,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -418,7 +396,7 @@ unit i_linux;
             name         : 'Linux for x86-64';
             shortname    : 'Linux';
             flags        : [tf_needs_symbol_size,tf_needs_dwarf_cfi,tf_smartlink_library,
-                            tf_library_needs_pic,tf_needs_symbol_type,tf_files_case_sensitive,tf_use_function_relative_addresses];
+                            tf_library_needs_pic,tf_needs_symbol_type,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_has_winlike_resources];
             cpu          : cpu_x86_64;
             unit_env     : 'LINUXUNITS';
             extradefines : 'UNIX;HASUNIX';
@@ -448,7 +426,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_dwarf2;
             script       : script_unix;
             endian       : endian_little;
@@ -478,7 +456,7 @@ unit i_linux;
             name         : 'Linux for SPARC';
             shortname    : 'Linux';
             flags        : [tf_needs_symbol_size,tf_library_needs_pic,tf_needs_symbol_type,tf_files_case_sensitive,tf_smartlink_library,
-                            tf_use_function_relative_addresses,tf_requires_proper_alignment];
+                            tf_use_function_relative_addresses,tf_requires_proper_alignment,tf_has_winlike_resources];
             cpu          : cpu_SPARC;
             unit_env     : 'LINUXUNITS';
             extradefines : 'UNIX;HASUNIX';
@@ -508,7 +486,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_big;
@@ -539,7 +517,7 @@ unit i_linux;
             name         : 'Linux for ARMEL';
             shortname    : 'Linux';
             flags        : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,
-                            tf_use_function_relative_addresses,tf_requires_proper_alignment,tf_smartlink_sections,tf_smartlink_library];
+                            tf_use_function_relative_addresses,tf_requires_proper_alignment,tf_smartlink_sections,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_arm;
             unit_env     : 'LINUXUNITS';
             extradefines : 'UNIX;HASUNIX';
@@ -569,7 +547,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -599,7 +577,7 @@ unit i_linux;
             name         : 'Linux for ARM';
             shortname    : 'Linux';
             flags        : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,
-                            tf_use_function_relative_addresses,tf_requires_proper_alignment,tf_smartlink_sections,tf_smartlink_library];
+                            tf_use_function_relative_addresses,tf_requires_proper_alignment,tf_smartlink_sections,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_arm;
             unit_env     : 'LINUXUNITS';
             extradefines : 'UNIX;HASUNIX';
@@ -629,7 +607,7 @@ unit i_linux;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;

+ 9 - 6
compiler/systems/i_os2.pas

@@ -27,12 +27,15 @@ unit i_os2;
        systems;
 
     const
-       res_emxbind_info : tresinfo =
+       res_wrc_os2_info : tresinfo =
           (
-            id     : res_emxbind;
-            resbin : 'emxbind';
-            rescmd : '-b -r $RES $OBJ'
-            (* Not really used - see TLinkeros2.SetDefaultInfo in t_os2.pas. *)
+             id     : res_watcom_wrc_os2;
+             resbin : '';
+             rescmd : '';
+             rcbin  : 'wrc';
+             rccmd  : '-r -zm -q -bt=os2 -fo=$RES $RC';
+             resourcefileclass : nil;
+             resflags : [res_single_file];
           );
 
        system_i386_os2_info : tsysteminfo =
@@ -70,7 +73,7 @@ unit i_os2;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar;
-            res          : res_emxbind;
+            res          : res_watcom_wrc_os2;
             dbg          : dbg_stabs;
             script       : script_dos;
             endian       : endian_little;

+ 5 - 5
compiler/systems/i_sunos.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Peter Vreman
+    Copyright (c) 1998-2008 by Peter Vreman
 
     This unit implements support information structures for solaris
 
@@ -32,7 +32,7 @@ unit i_sunos;
             system       : system_i386_solaris;
             name         : 'Solaris for i386';
             shortname    : 'solaris';
-            flags        : [tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library];
+            flags        : [tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_i386;
             unit_env     : 'SOLARISUNITS';
             extradefines : 'UNIX;LIBC;SUNOS;HASUNIX';
@@ -62,7 +62,7 @@ unit i_sunos;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_gar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_little;
@@ -92,7 +92,7 @@ unit i_sunos;
             name         : 'Solaris for SPARC';
             shortname    : 'solaris';
             flags        : [tf_needs_symbol_size,tf_under_development,tf_files_case_sensitive,tf_use_function_relative_addresses,
-                            tf_requires_proper_alignment,tf_smartlink_library];
+                            tf_requires_proper_alignment,tf_smartlink_library,tf_has_winlike_resources];
             cpu          : cpu_SPARC;
             unit_env     : 'SOLARISUNITS';
             extradefines : 'UNIX;LIBC;SUNOS;HASUNIX';
@@ -122,7 +122,7 @@ unit i_sunos;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_gar;
-            res          : res_none;
+            res          : res_elf;
             dbg          : dbg_stabs;
             script       : script_unix;
             endian       : endian_big;

+ 8 - 6
compiler/systems/i_win.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Peter Vreman
+    Copyright (c) 1998-2008 by Peter Vreman
 
     This unit implements support information structures for win32
 
@@ -35,7 +35,7 @@ unit i_win;
             flags        : [tf_files_case_aware,tf_has_dllscanner,tf_use_function_relative_addresses,tf_smartlink_library
                             ,tf_smartlink_sections{,tf_section_threadvars}{,tf_needs_dwarf_cfi},
                             tf_winlikewidestring,tf_no_pic_supported,
-                            tf_no_generic_stackcheck];
+                            tf_no_generic_stackcheck,tf_has_winlike_resources];
             cpu          : cpu_i386;
             unit_env     : 'WIN32UNITS';
             extradefines : 'MSWINDOWS;WINDOWS';
@@ -96,7 +96,7 @@ unit i_win;
             shortname    : 'Win64';
             flags        : [tf_files_case_aware,tf_has_dllscanner,tf_use_function_relative_addresses,
                             tf_smartlink_sections,tf_smartlink_library,tf_winlikewidestring,tf_no_pic_supported,
-                            tf_no_generic_stackcheck];
+                            tf_no_generic_stackcheck,tf_has_winlike_resources];
             cpu          : cpu_x86_64;
             unit_env     : 'WIN64UNITS';
             extradefines : 'MSWINDOWS;WINDOWS';
@@ -156,7 +156,8 @@ unit i_win;
             name         : 'WinCE for ARM';
             shortname    : 'WinCE';
             flags        : [tf_files_case_aware,tf_use_function_relative_addresses{,tf_winlikewidestring},
-                            tf_smartlink_sections,tf_requires_proper_alignment,tf_no_pic_supported];
+                            tf_smartlink_sections,tf_requires_proper_alignment,tf_no_pic_supported,
+                            tf_has_winlike_resources];
             cpu          : cpu_arm;
             unit_env     : '';
             extradefines : 'UNDER_CE;WINDOWS;UNICODE';
@@ -186,7 +187,7 @@ unit i_win;
             link         : nil;
             linkextern   : nil;
             ar           : ar_gnu_ar_scripted;
-            res          : res_gnu_wince_windres;
+            res          : res_gnu_windres;
             dbg          : dbg_stabs;
             script       : script_dos;
             endian       : endian_little;
@@ -216,7 +217,8 @@ unit i_win;
             name         : 'WinCE for i386';
             shortname    : 'WinCE';
             flags        : [tf_files_case_aware,tf_use_function_relative_addresses
-                            {,tf_winlikewidestring},tf_smartlink_sections,tf_no_pic_supported];
+                            {,tf_winlikewidestring},tf_smartlink_sections,tf_no_pic_supported,
+                            tf_has_winlike_resources];
             cpu          : cpu_i386;
             unit_env     : '';
             extradefines : 'UNDER_CE;WINDOWS;UNICODE';

+ 4 - 1
compiler/systems/t_bsd.pas

@@ -36,7 +36,7 @@ implementation
     verbose,systems,globtype,globals,
     symconst,script,
     fmodule,aasmbase,aasmtai,aasmdata,aasmcpu,cpubase,symsym,symdef,
-    import,export,link,i_bsd,
+    import,export,link,comprsrc,rescmn,i_bsd,
     cgutils,cgbase,cgobj,cpuinfo,ogbase;
 
   type
@@ -820,4 +820,7 @@ initialization
   RegisterExport(system_powerpc64_darwin,texportlibbsd);
   RegisterTarget(system_powerpc64_darwin_info);
 {$endif powerpc64}
+
+  RegisterRes(res_elf_info,TWinLikeResourceFile);
+  RegisterRes(res_macho_info,TWinLikeResourceFile);
 end.

+ 1 - 1
compiler/systems/t_emx.pas

@@ -526,6 +526,6 @@ end;
 initialization
   RegisterExternalLinker(system_i386_emx_info,TLinkerEMX);
   RegisterImport(system_i386_emx,TImportLibEMX);
-  RegisterRes(res_emxbind_info,TResourceFile);
+  RegisterRes(res_wrc_os2_info,TResourceFile);
   RegisterTarget(system_i386_emx_info);
 end.

+ 3 - 24
compiler/systems/t_linux.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Peter Vreman
+    Copyright (c) 1998-2008 by Peter Vreman
 
     This unit implements support import,export,link routines
     for the (i386) Linux target
@@ -57,7 +57,6 @@ interface
       procedure InitSysInitUnitName;override;
       function  MakeExecutable:boolean;override;
       function  MakeSharedLibrary:boolean;override;
-      function  postprocessexecutable(const fn : string;isdll:boolean):boolean;
       procedure LoadPredefinedLibraryOrder; override;
     end;
 
@@ -73,7 +72,7 @@ implementation
     aasmbase,aasmtai,aasmdata,aasmcpu,cpubase,
     cgbase,cgobj,cgutils,ogbase,ncgutil,
     comprsrc,
-    i_linux
+    rescmn, i_linux
     ;
 
 {*****************************************************************************
@@ -1083,10 +1082,6 @@ begin
   if (success) and not(cs_link_nolink in current_settings.globalswitches) then
    DeleteFile(outputexedir+Info.ResName);
 
-  if (success) then
-    success:=PostProcessExecutable(current_module.exefilename^,false);
-
-
   MakeExecutable:=success;   { otherwise a recursive call to link method }
 end;
 
@@ -1139,21 +1134,6 @@ begin
   MakeSharedLibrary:=success;   { otherwise a recursive call to link method }
 end;
 
-
-function tlinkerLinux.postprocessexecutable(const fn : string;isdll:boolean):boolean;
-var
-  cmdstr: string;
-begin
-  result:=True;
-  if HasResources and
-     (target_res.id=res_elf) then
-    begin
-      cmdstr:=' -f -i '+maybequoted(fn);
-      result:=DoExec(FindUtil(utilsprefix+'fpcres'),cmdstr,false,false);
-    end;
-end;
-
-
 {*****************************************************************************
                                   Initialize
 *****************************************************************************}
@@ -1164,7 +1144,6 @@ initialization
   RegisterImport(system_i386_linux,timportliblinux);
   RegisterExport(system_i386_linux,texportliblinux);
   RegisterTarget(system_i386_linux_info);
-  RegisterRes(res_elf32_info,TWinLikeResourceFile);
 
   RegisterExternalLinker(system_x86_6432_linux_info,TLinkerLinux);
   RegisterImport(system_x86_6432_linux,timportliblinux);
@@ -1200,7 +1179,6 @@ initialization
   RegisterImport(system_x86_64_linux,timportliblinux);
   RegisterExport(system_x86_64_linux,texportliblinux);
   RegisterTarget(system_x86_64_linux_info);
-  RegisterRes(res_elf64_info,TWinLikeResourceFile);
 {$endif x86_64}
 {$ifdef SPARC}
   RegisterExternalLinker(system_sparc_linux_info,TLinkerLinux);
@@ -1214,4 +1192,5 @@ initialization
   RegisterExport(system_arm_linux,texportliblinux);
   RegisterTarget(system_arm_linux_info);
 {$endif ARM}
+  RegisterRes(res_elf_info,TWinLikeResourceFile);
 end.

+ 1 - 1
compiler/systems/t_os2.pas

@@ -552,6 +552,6 @@ end;
 initialization
   RegisterExternalLinker(system_i386_os2_info,TLinkerOS2);
   RegisterImport(system_i386_os2,TImportLibOS2);
-{  RegisterRes(res_emxbind_info);}
+{  RegisterRes(res_wrc_os2_info,TResourceFile);}
   RegisterTarget(system_i386_os2_info);
 end.

+ 4 - 2
compiler/systems/t_sunos.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Peter Vreman
+    Copyright (c) 1998-2008 by Peter Vreman
 
     This unit implements support import,export,link routines
     for the (i386) solaris target
@@ -40,7 +40,7 @@ implementation
     symconst,script,
     fmodule,aasmbase,aasmtai,aasmdata,aasmcpu,cpubase,symsym,symdef,
     cgobj,
-    import,export,link,i_sunos,ogbase;
+    import,export,link,comprsrc,rescmn,i_sunos,ogbase;
 
   type
     timportlibsolaris=class(timportlib)
@@ -470,4 +470,6 @@ initialization
   RegisterExport(system_sparc_solaris,TExportLibsolaris);
   RegisterTarget(system_sparc_solaris_info);
 {$endif sparc}
+
+  RegisterRes(res_elf_info,TWinLikeResourceFile);
 end.

+ 10 - 47
compiler/systems/t_win.pas

@@ -1,5 +1,5 @@
 {
-    Copyright (c) 1998-2002 by Peter Vreman
+    Copyright (c) 1998-2008 by Peter Vreman
 
     This unit implements support import,export,link routines
     for the (i386) Win32 target
@@ -90,12 +90,6 @@ interface
         function Scan(const binname:string):boolean;override;
       end;
 
-
-      TWinResourceFile = class(TWinLikeResourceFile)
-        procedure PostProcessResourcefile(const s : ansistring);override;
-      end;
-
-
 implementation
 
   uses
@@ -109,32 +103,23 @@ implementation
     res_gnu_windres_info : tresinfo =
         (
           id     : res_gnu_windres;
-          resbin : 'windres';
-          rescmd : '--include $INC -O coff -o $OBJ $RES';
+          resbin : 'fpcres';
+          rescmd : '-o $OBJ -a $ARCH -of coff $DBG';
           rcbin  : 'windres';
           rccmd  : '--include $INC -O res -o $RES $RC';
           resourcefileclass : nil;
+          resflags : [];
         );
-
-    res_gnu_wince_windres_info : tresinfo =
-        (
-          id     : res_gnu_wince_windres;
-          resbin : 'windres';
-          rescmd : '--include $INC -O coff -o $OBJ $RES';
-          rcbin  : 'windres';
-          rccmd  : '--include $INC -O res -o $RES $RC';
-          resourcefileclass : nil;
-        );
-
 {$ifdef x86_64}
     res_win64_gorc_info : tresinfo =
         (
           id     : res_win64_gorc;
-          resbin : 'gorc';
-          rescmd : '/machine x64 /nw /ni /o /fo $OBJ $RES';
+          resbin : 'fpcres';
+          rescmd : '-o $OBJ -a $ARCH -of coff $DBG';
           rcbin  : 'gorc';
           rccmd  : '/machine x64 /nw /ni /r /fo $RES $RC';
           resourcefileclass : nil;
+          resflags : [];
         );
 {$endif x86_64}
 
@@ -1757,28 +1742,6 @@ implementation
         result:=importfound;
       end;
 
-
-{****************************************************************************
-                            TWinResourceFile
-****************************************************************************}
-
-procedure TWinResourceFile.PostProcessResourcefile(const s : ansistring);
-{$ifdef arm}
-var
-  f : file;
-  w : word;
-{$endif arm}
-begin
-{$ifdef arm}
-  assign(f,s);
-  reset(f,1);
-  w:=COFF_MAGIC;
-  blockwrite(f,w,2);
-  close(f);
-{$endif arm}
-end;
-
-
 {*****************************************************************************
                                      Initialize
 *****************************************************************************}
@@ -1791,7 +1754,7 @@ initialization
   RegisterImport(system_i386_win32,TImportLibWin);
   RegisterExport(system_i386_win32,TExportLibWin);
   RegisterDLLScanner(system_i386_win32,TDLLScannerWin);
-  RegisterRes(res_gnu_windres_info,TWinResourceFile);
+  RegisterRes(res_gnu_windres_info,TWinLikeResourceFile);
   RegisterTarget(system_i386_win32_info);
   { WinCE }
   RegisterExternalLinker(system_i386_wince_info,TExternalLinkerWin);
@@ -1806,7 +1769,7 @@ initialization
   RegisterImport(system_x86_64_win64,TImportLibWin);
   RegisterExport(system_x86_64_win64,TExportLibWin);
   RegisterDLLScanner(system_x86_64_win64,TDLLScannerWin);
-  RegisterRes(res_win64_gorc_info,TWinResourceFile);
+  RegisterRes(res_win64_gorc_info,TWinLikeResourceFile);
   RegisterTarget(system_x64_win64_info);
 {$endif x86_64}
 {$ifdef arm}
@@ -1814,7 +1777,7 @@ initialization
   RegisterInternalLinker(system_arm_wince_info,TInternalLinkerWin);
   RegisterImport(system_arm_wince,TImportLibWin);
   RegisterExport(system_arm_wince,TExportLibWin);
-  RegisterRes(res_gnu_wince_windres_info,TWinResourceFile);
+  RegisterRes(res_gnu_windres_info,TWinLikeResourceFile);
   RegisterTarget(system_arm_wince_info);
 {$endif arm}
 end.

+ 155 - 213
packages/Makefile

@@ -1,12 +1,11 @@
 #
-# Don't edit, this file is generated by FPCMake Version 2.0.0 [2008/03/07]
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2007/09/10]
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-darwin x86_64-win64 x86_64-embedded arm-linux arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian powerpc64-linux powerpc64-darwin powerpc64-embedded avr-embedded
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-win64 x86_64-embedded arm-linux arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian powerpc64-linux powerpc64-embedded
 BSDs = freebsd netbsd openbsd darwin
 UNIXs = linux $(BSDs) solaris qnx
 LIMIT83fs = go32v2 os2 emx watcom
-OSNeedsComspecToRunBatch = go32v2 watcom
 FORCE:
 .PHONY: FORCE
 override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH)))
@@ -57,11 +56,6 @@ else
 SRCBATCHEXT=.bat
 endif
 endif
-ifdef COMSPEC
-ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),)
-RUNBATCH=$(COMSPEC) /C
-endif
-endif
 ifdef inUnix
 PATHSEP=/
 else
@@ -108,11 +102,7 @@ ifndef FPC
 FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
 ifneq ($(FPCPROG),)
 FPCPROG:=$(firstword $(FPCPROG))
-ifneq ($(CPU_TARGET),)
-FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB)
-else
 FPC:=$(shell $(FPCPROG) -PB)
-endif
 ifneq ($(findstring Error,$(FPC)),)
 override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
 endif
@@ -241,166 +231,157 @@ UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
 endif
 PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
 ifeq ($(FULL_TARGET),i386-linux)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph libc unixutil graph pxlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph libc unixutil graph pxlib
 endif
 ifeq ($(FULL_TARGET),i386-go32v2)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv graph unzip gdbint
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv graph unzip gdbint
 endif
 ifeq ($(FULL_TARGET),i386-win32)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv winunits-base winunits-jedi fcl-web ibase mysql zlib oracle odbc postgres sqlite imagemagick gdbint libpng mad tcl opengl gtk1 gtk2 a52 cdrom fpgtk openal fftw lua oggvorbis sdl openssl graph pcap httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv winunits-base winunits-jedi fcl-web ibase mysql zlib oracle odbc postgres sqlite imagemagick gdbint libpng mad tcl opengl gtk1 gtk2 a52 cdrom fpgtk openal fftw lua oggvorbis sdl openssl graph pcap httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),i386-os2)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv zlib libpng x11 tcl fpgtk rexx os2units gtk1 imlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv zlib libpng x11 tcl fpgtk rexx os2units gtk1 imlib
 endif
 ifeq ($(FULL_TARGET),i386-freebsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),i386-beos)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),i386-netbsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),i386-solaris)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 bfd svgalib imlib utmp  fpgtk xforms fftw pcap ggi  openssl gnome1 httpd22 numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 bfd svgalib imlib utmp  fpgtk xforms fftw pcap ggi  openssl gnome1 httpd22 numlib
 endif
 ifeq ($(FULL_TARGET),i386-qnx)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),i386-netware)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv zlib unzip
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv zlib unzip
 endif
 ifeq ($(FULL_TARGET),i386-openbsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc  postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc  postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),i386-wdosx)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),i386-darwin)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi openssl gnome1 httpd22 numlib graph univint sdl
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi openssl gnome1 httpd22 numlib graph univint sdl
 endif
 ifeq ($(FULL_TARGET),i386-emx)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv zlib libpng x11 tcl fpgtk rexx os2units gtk1 imlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv zlib libpng x11 tcl fpgtk rexx os2units gtk1 imlib
 endif
 ifeq ($(FULL_TARGET),i386-watcom)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),i386-netwlibc)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv zlib unzip
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv zlib unzip
 endif
 ifeq ($(FULL_TARGET),i386-wince)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fcl-web tcl fftw unzip zlib sqlite mysql ibase postgres oracle odbc sdl openssl oggvorbis numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fcl-web tcl fftw unzip zlib sqlite mysql ibase postgres oracle odbc sdl openssl oggvorbis numlib
 endif
 ifeq ($(FULL_TARGET),i386-embedded)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),i386-symbian)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),m68k-linux)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
 endif
 ifeq ($(FULL_TARGET),m68k-freebsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),m68k-netbsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),m68k-amiga)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  amunits
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  amunits
 endif
 ifeq ($(FULL_TARGET),m68k-atari)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),m68k-openbsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc  postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc  postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),m68k-palmos)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  palmunits
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  palmunits
 endif
 ifeq ($(FULL_TARGET),m68k-embedded)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),powerpc-linux)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
 endif
 ifeq ($(FULL_TARGET),powerpc-netbsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),powerpc-amiga)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  amunits
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  amunits
 endif
 ifeq ($(FULL_TARGET),powerpc-macos)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),powerpc-darwin)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi openssl gnome1 httpd22 numlib graph univint sdl
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi openssl gnome1 httpd22 numlib graph univint sdl
 endif
 ifeq ($(FULL_TARGET),powerpc-morphos)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),powerpc-embedded)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),sparc-linux)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
 endif
 ifeq ($(FULL_TARGET),sparc-netbsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),sparc-solaris)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 bfd svgalib imlib utmp  fpgtk xforms fftw pcap ggi  openssl gnome1 httpd22 numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 bfd svgalib imlib utmp  fpgtk xforms fftw pcap ggi  openssl gnome1 httpd22 numlib
 endif
 ifeq ($(FULL_TARGET),sparc-embedded)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),x86_64-linux)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
 endif
 ifeq ($(FULL_TARGET),x86_64-freebsd)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 httpd22 pxlib numlib
-endif
-ifeq ($(FULL_TARGET),x86_64-darwin)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi openssl gnome1 httpd22 numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick gdbint libpng x11 gdbm tcl syslog libcurl opengl cairo  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi sdl openssl graph gnome1 gtk1 gtk2 httpd22 pxlib numlib
 endif
 ifeq ($(FULL_TARGET),x86_64-win64)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv winunits-base winunits-jedi fcl-web ibase mysql zlib oracle odbc postgres sqlite imagemagick tcl opengl gtk1 gtk2 fpgtk fftw sdl openssl cdrom numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv winunits-base winunits-jedi fcl-web ibase mysql zlib oracle odbc postgres sqlite imagemagick tcl opengl gtk1 gtk2 fpgtk fftw sdl openssl cdrom numlib
 endif
 ifeq ($(FULL_TARGET),x86_64-embedded)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),arm-linux)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
 endif
 ifeq ($(FULL_TARGET),arm-palmos)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  palmunits
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  palmunits
 endif
 ifeq ($(FULL_TARGET),arm-wince)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fcl-web tcl fftw unzip zlib sqlite mysql ibase postgres oracle odbc sdl openssl oggvorbis numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fcl-web tcl fftw unzip zlib sqlite mysql ibase postgres oracle odbc sdl openssl oggvorbis numlib
 endif
 ifeq ($(FULL_TARGET),arm-gba)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),arm-nds)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),arm-embedded)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),arm-symbian)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 ifeq ($(FULL_TARGET),powerpc64-linux)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
-endif
-ifeq ($(FULL_TARGET),powerpc64-darwin)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm  fv fcl-web fcl-async ibase mysql ncurses zlib oracle odbc postgres sqlite pthreads imagemagick libpng x11 gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  bfd aspell svgalib imlib utmp  fpgtk xforms fftw pcap ggi openssl gnome1 httpd22 numlib
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res  fv fcl-web fcl-async ibase mysql ncurses unzip zlib oracle dbus odbc postgres sqlite pthreads imagemagick gdbint libpng x11 uuid ldap modplug dts mad  gdbm tcl syslog libcurl opengl cairo gtk1 gtk2  a52 bfd aspell svgalib newt cdrom users  imlib utmp  fpgtk openal lua oggvorbis xforms fftw pcap ggi sdl openssl gnome1 httpd22 pxlib numlib graph
 endif
 ifeq ($(FULL_TARGET),powerpc64-embedded)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
-endif
-ifeq ($(FULL_TARGET),avr-embedded)
-override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+override TARGET_DIRS+=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 endif
 override INSTALL_FPCPACKAGE=y
 override INSTALL_FPCSUBDIR=packages
@@ -1165,7 +1146,7 @@ override FPCOPT+=-FD$(NEW_BINUTILS_PATH)
 endif
 ifndef CROSSBOOTSTRAP
 ifneq ($(BINUTILSPREFIX),)
-override FPCOPT+=-XP$(BINUTILSPREFIX)
+override FPCOPT+=-XP$(BINUTILSPREFIX) 
 endif
 ifneq ($(BINUTILSPREFIX),)
 override FPCOPT+=-Xr$(RLINKPATH)
@@ -1297,13 +1278,9 @@ ifeq (,$(findstring -s ,$(COMPILER)))
 EXECPPAS=
 else
 ifeq ($(FULL_SOURCE),$(FULL_TARGET))
-ifdef RUNBATCH
-EXECPPAS:=@$(RUNBATCH) $(PPAS)
-else
 EXECPPAS:=@$(PPAS)
 endif
 endif
-endif
 ifdef TARGET_RSTS
 override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS))
 override CLEANRSTFILES+=$(RSTFILES)
@@ -1499,6 +1476,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -1577,6 +1555,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_GRAPH=1
 TARGET_DIRS_UNZIP=1
@@ -1600,6 +1579,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_WINUNITS-BASE=1
 TARGET_DIRS_WINUNITS-JEDI=1
@@ -1652,6 +1632,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_ZLIB=1
 TARGET_DIRS_LIBPNG=1
@@ -1681,6 +1662,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -1741,6 +1723,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -1800,6 +1783,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -1859,6 +1843,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -1913,6 +1898,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),i386-netware)
 TARGET_DIRS_HASH=1
@@ -1932,6 +1918,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_ZLIB=1
 TARGET_DIRS_UNZIP=1
@@ -1954,6 +1941,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2013,6 +2001,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),i386-darwin)
 TARGET_DIRS_HASH=1
@@ -2032,6 +2021,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2091,6 +2081,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_ZLIB=1
 TARGET_DIRS_LIBPNG=1
@@ -2120,6 +2111,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),i386-netwlibc)
 TARGET_DIRS_HASH=1
@@ -2139,6 +2131,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_ZLIB=1
 TARGET_DIRS_UNZIP=1
@@ -2161,6 +2154,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_TCL=1
 TARGET_DIRS_FFTW=1
@@ -2195,6 +2189,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),i386-symbian)
 TARGET_DIRS_HASH=1
@@ -2214,6 +2209,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),m68k-linux)
 TARGET_DIRS_HASH=1
@@ -2233,6 +2229,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2307,6 +2304,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2367,6 +2365,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2426,6 +2425,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_AMUNITS=1
 endif
 ifeq ($(FULL_TARGET),m68k-atari)
@@ -2446,6 +2446,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),m68k-openbsd)
 TARGET_DIRS_HASH=1
@@ -2465,6 +2466,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2524,6 +2526,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_PALMUNITS=1
 endif
 ifeq ($(FULL_TARGET),m68k-embedded)
@@ -2544,6 +2547,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),powerpc-linux)
 TARGET_DIRS_HASH=1
@@ -2563,6 +2567,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2637,6 +2642,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2696,6 +2702,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_AMUNITS=1
 endif
 ifeq ($(FULL_TARGET),powerpc-macos)
@@ -2716,6 +2723,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),powerpc-darwin)
 TARGET_DIRS_HASH=1
@@ -2735,6 +2743,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2794,6 +2803,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),powerpc-embedded)
 TARGET_DIRS_HASH=1
@@ -2813,6 +2823,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),sparc-linux)
 TARGET_DIRS_HASH=1
@@ -2832,6 +2843,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2906,6 +2918,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -2965,6 +2978,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -3019,6 +3033,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),x86_64-linux)
 TARGET_DIRS_HASH=1
@@ -3038,6 +3053,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -3112,6 +3128,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -3154,62 +3171,6 @@ TARGET_DIRS_HTTPD22=1
 TARGET_DIRS_PXLIB=1
 TARGET_DIRS_NUMLIB=1
 endif
-ifeq ($(FULL_TARGET),x86_64-darwin)
-TARGET_DIRS_HASH=1
-TARGET_DIRS_PASJPEG=1
-TARGET_DIRS_PASZLIB=1
-TARGET_DIRS_FPMKUNIT=1
-TARGET_DIRS_FCL-BASE=1
-TARGET_DIRS_FCL-DB=1
-TARGET_DIRS_FCL-IMAGE=1
-TARGET_DIRS_FCL-NET=1
-TARGET_DIRS_FCL-PASSRC=1
-TARGET_DIRS_FCL-REGISTRY=1
-TARGET_DIRS_FCL-XML=1
-TARGET_DIRS_FCL-FPCUNIT=1
-TARGET_DIRS_FCL-JSON=1
-TARGET_DIRS_FCL-PROCESS=1
-TARGET_DIRS_UNZIP=1
-TARGET_DIRS_REGEXPR=1
-TARGET_DIRS_CHM=1
-TARGET_DIRS_FV=1
-TARGET_DIRS_FCL-WEB=1
-TARGET_DIRS_FCL-ASYNC=1
-TARGET_DIRS_IBASE=1
-TARGET_DIRS_MYSQL=1
-TARGET_DIRS_NCURSES=1
-TARGET_DIRS_ZLIB=1
-TARGET_DIRS_ORACLE=1
-TARGET_DIRS_ODBC=1
-TARGET_DIRS_POSTGRES=1
-TARGET_DIRS_SQLITE=1
-TARGET_DIRS_PTHREADS=1
-TARGET_DIRS_IMAGEMAGICK=1
-TARGET_DIRS_LIBPNG=1
-TARGET_DIRS_X11=1
-TARGET_DIRS_GDBM=1
-TARGET_DIRS_TCL=1
-TARGET_DIRS_SYSLOG=1
-TARGET_DIRS_LIBCURL=1
-TARGET_DIRS_OPENGL=1
-TARGET_DIRS_CAIRO=1
-TARGET_DIRS_GTK1=1
-TARGET_DIRS_GTK2=1
-TARGET_DIRS_BFD=1
-TARGET_DIRS_ASPELL=1
-TARGET_DIRS_SVGALIB=1
-TARGET_DIRS_IMLIB=1
-TARGET_DIRS_UTMP=1
-TARGET_DIRS_FPGTK=1
-TARGET_DIRS_XFORMS=1
-TARGET_DIRS_FFTW=1
-TARGET_DIRS_PCAP=1
-TARGET_DIRS_GGI=1
-TARGET_DIRS_OPENSSL=1
-TARGET_DIRS_GNOME1=1
-TARGET_DIRS_HTTPD22=1
-TARGET_DIRS_NUMLIB=1
-endif
 ifeq ($(FULL_TARGET),x86_64-win64)
 TARGET_DIRS_HASH=1
 TARGET_DIRS_PASJPEG=1
@@ -3228,6 +3189,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_WINUNITS-BASE=1
 TARGET_DIRS_WINUNITS-JEDI=1
@@ -3269,6 +3231,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),arm-linux)
 TARGET_DIRS_HASH=1
@@ -3288,6 +3251,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -3362,6 +3326,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_PALMUNITS=1
 endif
 ifeq ($(FULL_TARGET),arm-wince)
@@ -3382,6 +3347,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_TCL=1
 TARGET_DIRS_FFTW=1
@@ -3416,6 +3382,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),arm-nds)
 TARGET_DIRS_HASH=1
@@ -3435,6 +3402,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),arm-embedded)
 TARGET_DIRS_HASH=1
@@ -3454,6 +3422,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),arm-symbian)
 TARGET_DIRS_HASH=1
@@ -3473,6 +3442,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifeq ($(FULL_TARGET),powerpc64-linux)
 TARGET_DIRS_HASH=1
@@ -3492,6 +3462,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 TARGET_DIRS_FV=1
 TARGET_DIRS_FCL-WEB=1
 TARGET_DIRS_FCL-ASYNC=1
@@ -3548,62 +3519,6 @@ TARGET_DIRS_PXLIB=1
 TARGET_DIRS_NUMLIB=1
 TARGET_DIRS_GRAPH=1
 endif
-ifeq ($(FULL_TARGET),powerpc64-darwin)
-TARGET_DIRS_HASH=1
-TARGET_DIRS_PASJPEG=1
-TARGET_DIRS_PASZLIB=1
-TARGET_DIRS_FPMKUNIT=1
-TARGET_DIRS_FCL-BASE=1
-TARGET_DIRS_FCL-DB=1
-TARGET_DIRS_FCL-IMAGE=1
-TARGET_DIRS_FCL-NET=1
-TARGET_DIRS_FCL-PASSRC=1
-TARGET_DIRS_FCL-REGISTRY=1
-TARGET_DIRS_FCL-XML=1
-TARGET_DIRS_FCL-FPCUNIT=1
-TARGET_DIRS_FCL-JSON=1
-TARGET_DIRS_FCL-PROCESS=1
-TARGET_DIRS_UNZIP=1
-TARGET_DIRS_REGEXPR=1
-TARGET_DIRS_CHM=1
-TARGET_DIRS_FV=1
-TARGET_DIRS_FCL-WEB=1
-TARGET_DIRS_FCL-ASYNC=1
-TARGET_DIRS_IBASE=1
-TARGET_DIRS_MYSQL=1
-TARGET_DIRS_NCURSES=1
-TARGET_DIRS_ZLIB=1
-TARGET_DIRS_ORACLE=1
-TARGET_DIRS_ODBC=1
-TARGET_DIRS_POSTGRES=1
-TARGET_DIRS_SQLITE=1
-TARGET_DIRS_PTHREADS=1
-TARGET_DIRS_IMAGEMAGICK=1
-TARGET_DIRS_LIBPNG=1
-TARGET_DIRS_X11=1
-TARGET_DIRS_GDBM=1
-TARGET_DIRS_TCL=1
-TARGET_DIRS_SYSLOG=1
-TARGET_DIRS_LIBCURL=1
-TARGET_DIRS_OPENGL=1
-TARGET_DIRS_CAIRO=1
-TARGET_DIRS_GTK1=1
-TARGET_DIRS_GTK2=1
-TARGET_DIRS_BFD=1
-TARGET_DIRS_ASPELL=1
-TARGET_DIRS_SVGALIB=1
-TARGET_DIRS_IMLIB=1
-TARGET_DIRS_UTMP=1
-TARGET_DIRS_FPGTK=1
-TARGET_DIRS_XFORMS=1
-TARGET_DIRS_FFTW=1
-TARGET_DIRS_PCAP=1
-TARGET_DIRS_GGI=1
-TARGET_DIRS_OPENSSL=1
-TARGET_DIRS_GNOME1=1
-TARGET_DIRS_HTTPD22=1
-TARGET_DIRS_NUMLIB=1
-endif
 ifeq ($(FULL_TARGET),powerpc64-embedded)
 TARGET_DIRS_HASH=1
 TARGET_DIRS_PASJPEG=1
@@ -3622,25 +3537,7 @@ TARGET_DIRS_FCL-PROCESS=1
 TARGET_DIRS_UNZIP=1
 TARGET_DIRS_REGEXPR=1
 TARGET_DIRS_CHM=1
-endif
-ifeq ($(FULL_TARGET),avr-embedded)
-TARGET_DIRS_HASH=1
-TARGET_DIRS_PASJPEG=1
-TARGET_DIRS_PASZLIB=1
-TARGET_DIRS_FPMKUNIT=1
-TARGET_DIRS_FCL-BASE=1
-TARGET_DIRS_FCL-DB=1
-TARGET_DIRS_FCL-IMAGE=1
-TARGET_DIRS_FCL-NET=1
-TARGET_DIRS_FCL-PASSRC=1
-TARGET_DIRS_FCL-REGISTRY=1
-TARGET_DIRS_FCL-XML=1
-TARGET_DIRS_FCL-FPCUNIT=1
-TARGET_DIRS_FCL-JSON=1
-TARGET_DIRS_FCL-PROCESS=1
-TARGET_DIRS_UNZIP=1
-TARGET_DIRS_REGEXPR=1
-TARGET_DIRS_CHM=1
+TARGET_DIRS_FCL-RES=1
 endif
 ifdef TARGET_DIRS_HASH
 hash_all:
@@ -4407,6 +4304,51 @@ chm:
 	$(MAKE) -C chm all
 .PHONY: chm_all chm_debug chm_smart chm_release chm_units chm_examples chm_shared chm_install chm_sourceinstall chm_exampleinstall chm_distinstall chm_zipinstall chm_zipsourceinstall chm_zipexampleinstall chm_zipdistinstall chm_clean chm_distclean chm_cleanall chm_info chm_makefiles chm
 endif
+ifdef TARGET_DIRS_FCL-RES
+fcl-res_all:
+	$(MAKE) -C fcl-res all
+fcl-res_debug:
+	$(MAKE) -C fcl-res debug
+fcl-res_smart:
+	$(MAKE) -C fcl-res smart
+fcl-res_release:
+	$(MAKE) -C fcl-res release
+fcl-res_units:
+	$(MAKE) -C fcl-res units
+fcl-res_examples:
+	$(MAKE) -C fcl-res examples
+fcl-res_shared:
+	$(MAKE) -C fcl-res shared
+fcl-res_install:
+	$(MAKE) -C fcl-res install
+fcl-res_sourceinstall:
+	$(MAKE) -C fcl-res sourceinstall
+fcl-res_exampleinstall:
+	$(MAKE) -C fcl-res exampleinstall
+fcl-res_distinstall:
+	$(MAKE) -C fcl-res distinstall
+fcl-res_zipinstall:
+	$(MAKE) -C fcl-res zipinstall
+fcl-res_zipsourceinstall:
+	$(MAKE) -C fcl-res zipsourceinstall
+fcl-res_zipexampleinstall:
+	$(MAKE) -C fcl-res zipexampleinstall
+fcl-res_zipdistinstall:
+	$(MAKE) -C fcl-res zipdistinstall
+fcl-res_clean:
+	$(MAKE) -C fcl-res clean
+fcl-res_distclean:
+	$(MAKE) -C fcl-res distclean
+fcl-res_cleanall:
+	$(MAKE) -C fcl-res cleanall
+fcl-res_info:
+	$(MAKE) -C fcl-res info
+fcl-res_makefiles:
+	$(MAKE) -C fcl-res makefiles
+fcl-res:
+	$(MAKE) -C fcl-res all
+.PHONY: fcl-res_all fcl-res_debug fcl-res_smart fcl-res_release fcl-res_units fcl-res_examples fcl-res_shared fcl-res_install fcl-res_sourceinstall fcl-res_exampleinstall fcl-res_distinstall fcl-res_zipinstall fcl-res_zipsourceinstall fcl-res_zipexampleinstall fcl-res_zipdistinstall fcl-res_clean fcl-res_distclean fcl-res_cleanall fcl-res_info fcl-res_makefiles fcl-res
+endif
 ifdef TARGET_DIRS_FV
 fv_all:
 	$(MAKE) -C fv all
@@ -7347,11 +7289,11 @@ fcl-db_release: fcl-base_release
 fcl-db_shared: fcl-base_shared
 endif
 endif
-fcl_all: fcl-base_all fcl-xml_all fcl-fpcunit_all fcl-db_all fcl-web_all fcl-registry_all fcl-passrc_all fcl-image_all fcl-net_all fcl-json_all
-fcl_debug: fcl-base_debug fcl-xml_debug fcl-fpcunit_debug fcl-db_debug fcl-web_debug fcl-registry_debug fcl-passrc_debug fcl-image_debug fcl-net_debug fcl-json_debug
-fcl_smart: fcl-base_smart fcl-xml_smart fcl-fpcunit_smart fcl-db_smart fcl-web_smart fcl-registry_smart fcl-passrc_smart fcl-image_smart fcl-net_smart fcl-json_smart
-fcl_release: fcl-base_release fcl-xml_release fcl-fpcunit_release fcl-db_release fcl-web_release fcl-registry_release fcl-passrc_release fcl-image_release fcl-net_release fcl-json_release
-fcl_shared: fcl-base_shared fcl-xml_shared fcl-fpcunit_shared fcl-db_shared fcl-web_shared fcl-registry_shared fcl-passrc_shared fcl-image_shared fcl-net_shared fcl-json_shared
+fcl_all: fcl-base_all fcl-xml_all fcl-fpcunit_all fcl-db_all fcl-web_all fcl-registry_all fcl-passrc_all fcl-image_all fcl-net_all fcl-json_all fcl-res_all
+fcl_debug: fcl-base_debug fcl-xml_debug fcl-fpcunit_debug fcl-db_debug fcl-web_debug fcl-registry_debug fcl-passrc_debug fcl-image_debug fcl-net_debug fcl-json_debug fcl-res_debug
+fcl_smart: fcl-base_smart fcl-xml_smart fcl-fpcunit_smart fcl-db_smart fcl-web_smart fcl-registry_smart fcl-passrc_smart fcl-image_smart fcl-net_smart fcl-json_smart fcl-res_smart
+fcl_release: fcl-base_release fcl-xml_release fcl-fpcunit_release fcl-db_release fcl-web_release fcl-registry_release fcl-passrc_release fcl-image_release fcl-net_release fcl-json_release fcl-res_release
+fcl_shared: fcl-base_shared fcl-xml_shared fcl-fpcunit_shared fcl-db_shared fcl-web_shared fcl-registry_shared fcl-passrc_shared fcl-image_shared fcl-net_shared fcl-json_shared fcl-res_shared
 paszlib_all: hash_all
 paszlib_debug: hash_debug
 paszlib_smart: hash_smart

+ 6 - 6
packages/Makefile.fpc

@@ -3,7 +3,7 @@
 #
 
 [target]
-dirs=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm
+dirs=hash pasjpeg paszlib fpmkunit fcl-base fcl-db fcl-image fcl-net fcl-passrc fcl-registry fcl-xml fcl-fpcunit fcl-json  fcl-process unzip regexpr chm fcl-res
 dirs_linux_i386=libc unixutil graph pxlib
 dirs_i386_linux=graph
 dirs_x86_64_linux=graph
@@ -150,11 +150,11 @@ fcl-db_shared: fcl-base_shared
 endif
 endif
 
-fcl_all: fcl-base_all fcl-xml_all fcl-fpcunit_all fcl-db_all fcl-web_all fcl-registry_all fcl-passrc_all fcl-image_all fcl-net_all fcl-json_all
-fcl_debug: fcl-base_debug fcl-xml_debug fcl-fpcunit_debug fcl-db_debug fcl-web_debug fcl-registry_debug fcl-passrc_debug fcl-image_debug fcl-net_debug fcl-json_debug
-fcl_smart: fcl-base_smart fcl-xml_smart fcl-fpcunit_smart fcl-db_smart fcl-web_smart fcl-registry_smart fcl-passrc_smart fcl-image_smart fcl-net_smart fcl-json_smart
-fcl_release: fcl-base_release fcl-xml_release fcl-fpcunit_release fcl-db_release fcl-web_release fcl-registry_release fcl-passrc_release fcl-image_release fcl-net_release fcl-json_release
-fcl_shared: fcl-base_shared fcl-xml_shared fcl-fpcunit_shared fcl-db_shared fcl-web_shared fcl-registry_shared fcl-passrc_shared fcl-image_shared fcl-net_shared fcl-json_shared
+fcl_all: fcl-base_all fcl-xml_all fcl-fpcunit_all fcl-db_all fcl-web_all fcl-registry_all fcl-passrc_all fcl-image_all fcl-net_all fcl-json_all fcl-res_all
+fcl_debug: fcl-base_debug fcl-xml_debug fcl-fpcunit_debug fcl-db_debug fcl-web_debug fcl-registry_debug fcl-passrc_debug fcl-image_debug fcl-net_debug fcl-json_debug fcl-res_debug
+fcl_smart: fcl-base_smart fcl-xml_smart fcl-fpcunit_smart fcl-db_smart fcl-web_smart fcl-registry_smart fcl-passrc_smart fcl-image_smart fcl-net_smart fcl-json_smart fcl-res_smart
+fcl_release: fcl-base_release fcl-xml_release fcl-fpcunit_release fcl-db_release fcl-web_release fcl-registry_release fcl-passrc_release fcl-image_release fcl-net_release fcl-json_release fcl-res_release
+fcl_shared: fcl-base_shared fcl-xml_shared fcl-fpcunit_shared fcl-db_shared fcl-web_shared fcl-registry_shared fcl-passrc_shared fcl-image_shared fcl-net_shared fcl-json_shared fcl-res_shared
 
 paszlib_all: hash_all
 paszlib_debug: hash_debug

+ 2408 - 0
packages/fcl-res/Makefile

@@ -0,0 +1,2408 @@
+#
+# Don't edit, this file is generated by FPCMake Version 2.0.0 [2007/11/14]
+#
+default: all
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-darwin x86_64-win64 x86_64-embedded arm-linux arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian powerpc64-linux powerpc64-darwin powerpc64-embedded
+BSDs = freebsd netbsd openbsd darwin
+UNIXs = linux $(BSDs) solaris qnx
+LIMIT83fs = go32v2 os2 emx watcom
+OSNeedsComspecToRunBatch = go32v2 watcom
+FORCE:
+.PHONY: FORCE
+override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH)))
+ifneq ($(findstring darwin,$(OSTYPE)),)
+inUnix=1 #darwin
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+ifeq ($(findstring ;,$(PATH)),)
+inUnix=1
+SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH)))
+else
+SEARCHPATH:=$(subst ;, ,$(PATH))
+endif
+endif
+SEARCHPATH+=$(patsubst %/,%,$(subst \,/,$(dir $(MAKE))))
+PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH))))
+ifeq ($(PWD),)
+PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH))))
+ifeq ($(PWD),)
+$(error You need the GNU utils package to use this Makefile)
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=
+endif
+else
+PWD:=$(firstword $(PWD))
+SRCEXEEXT=.exe
+endif
+ifndef inUnix
+ifeq ($(OS),Windows_NT)
+inWinNT=1
+else
+ifdef OS2_SHELL
+inOS2=1
+endif
+endif
+else
+ifneq ($(findstring cygdrive,$(PATH)),)
+inCygWin=1
+endif
+endif
+ifdef inUnix
+SRCBATCHEXT=.sh
+else
+ifdef inOS2
+SRCBATCHEXT=.cmd
+else
+SRCBATCHEXT=.bat
+endif
+endif
+ifdef COMSPEC
+ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),)
+RUNBATCH=$(COMSPEC) /C
+endif
+endif
+ifdef inUnix
+PATHSEP=/
+else
+PATHSEP:=$(subst /,\,/)
+ifdef inCygWin
+PATHSEP=/
+endif
+endif
+ifdef PWD
+BASEDIR:=$(subst \,/,$(shell $(PWD)))
+ifdef inCygWin
+ifneq ($(findstring /cygdrive/,$(BASEDIR)),)
+BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR))
+BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR)))
+BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR))
+endif
+endif
+else
+BASEDIR=.
+endif
+ifdef inOS2
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO=echo
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+endif
+override DEFAULT_FPCDIR=../..
+ifndef FPC
+ifdef PP
+FPC=$(PP)
+endif
+endif
+ifndef FPC
+FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH))))
+ifneq ($(FPCPROG),)
+FPCPROG:=$(firstword $(FPCPROG))
+ifneq ($(CPU_TARGET),)
+FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB)
+else
+FPC:=$(shell $(FPCPROG) -PB)
+endif
+ifneq ($(findstring Error,$(FPC)),)
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+else
+override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH)))))
+endif
+endif
+override FPC:=$(subst $(SRCEXEEXT),,$(FPC))
+override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT)
+FOUNDFPC:=$(strip $(wildcard $(FPC)))
+ifeq ($(FOUNDFPC),)
+FOUNDFPC=$(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))
+ifeq ($(FOUNDFPC),)
+$(error Compiler $(FPC) not found)
+endif
+endif
+ifndef FPC_COMPILERINFO
+FPC_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO)
+endif
+ifndef FPC_VERSION
+FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO))
+endif
+export FPC FPC_VERSION FPC_COMPILERINFO
+unexport CHECKDEPEND ALLDEPENDENCIES
+ifndef CPU_TARGET
+ifdef CPU_TARGET_DEFAULT
+CPU_TARGET=$(CPU_TARGET_DEFAULT)
+endif
+endif
+ifndef OS_TARGET
+ifdef OS_TARGET_DEFAULT
+OS_TARGET=$(OS_TARGET_DEFAULT)
+endif
+endif
+ifneq ($(words $(FPC_COMPILERINFO)),5)
+FPC_COMPILERINFO+=$(shell $(FPC) -iSP)
+FPC_COMPILERINFO+=$(shell $(FPC) -iTP)
+FPC_COMPILERINFO+=$(shell $(FPC) -iSO)
+FPC_COMPILERINFO+=$(shell $(FPC) -iTO)
+endif
+ifndef CPU_SOURCE
+CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO))
+endif
+ifndef CPU_TARGET
+CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO))
+endif
+ifndef OS_SOURCE
+OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO))
+endif
+ifndef OS_TARGET
+OS_TARGET:=$(word 5,$(FPC_COMPILERINFO))
+endif
+FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+TARGETSUFFIX=$(OS_TARGET)
+SOURCESUFFIX=$(OS_SOURCE)
+else
+TARGETSUFFIX=$(FULL_TARGET)
+SOURCESUFFIX=$(FULL_SOURCE)
+endif
+ifneq ($(FULL_TARGET),$(FULL_SOURCE))
+CROSSCOMPILE=1
+endif
+ifeq ($(findstring makefile,$(MAKECMDGOALS)),)
+ifeq ($(findstring $(FULL_TARGET),$(MAKEFILETARGETS)),)
+$(error The Makefile doesn't support target $(FULL_TARGET), please run fpcmake first)
+endif
+endif
+ifneq ($(findstring $(OS_TARGET),$(BSDs)),)
+BSDhier=1
+endif
+ifeq ($(OS_TARGET),linux)
+linuxHier=1
+endif
+export OS_TARGET OS_SOURCE CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE TARGETSUFFIX SOURCESUFFIX CROSSCOMPILE
+ifdef FPCDIR
+override FPCDIR:=$(subst \,/,$(FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+else
+override FPCDIR=wrong
+endif
+ifdef DEFAULT_FPCDIR
+ifeq ($(FPCDIR),wrong)
+override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR))
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=wrong
+endif
+endif
+endif
+ifeq ($(FPCDIR),wrong)
+ifdef inUnix
+override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION)
+ifeq ($(wildcard $(FPCDIR)/units),)
+override FPCDIR=/usr/lib/fpc/$(FPC_VERSION)
+endif
+else
+override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH))))))
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(FPCDIR)/..
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR:=$(BASEDIR)
+ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),)
+override FPCDIR=c:/pp
+endif
+endif
+endif
+endif
+endif
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(FPCDIR)/bin/$(TARGETSUFFIX))
+endif
+ifndef BINUTILSPREFIX
+ifndef CROSSBINDIR
+ifdef CROSSCOMPILE
+BINUTILSPREFIX=$(CPU_TARGET)-$(OS_TARGET)-
+endif
+endif
+endif
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX))
+ifeq ($(UNITSDIR),)
+UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET))
+endif
+PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra)
+override PACKAGE_NAME=fcl-res
+override PACKAGE_VERSION=2.2.0
+ifeq ($(FULL_TARGET),i386-linux)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override TARGET_UNITS+=acceleratorsresource bitmapresource coffconsts coffreader cofftypes coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource groupresource icocurtypes machoconsts machoreader machotypes machowriter resdatastream resfactory resmerger resource resourcetree resreader reswriter stringtableresource strtable versionconsts versionresource versiontypes winpeimagereader
+endif
+ifeq ($(FULL_TARGET),i386-linux)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override TARGET_RSTS+=versiontypes stringtableresource resource resfactory
+endif
+override INSTALL_FPCPACKAGE=y
+ifeq ($(FULL_TARGET),i386-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override COMPILER_OPTIONS+=-S2h
+endif
+ifeq ($(FULL_TARGET),i386-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+override COMPILER_SOURCEDIR+=src
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+override COMPILER_SOURCEDIR+=src
+endif
+ifdef REQUIRE_UNITSDIR
+override UNITSDIR+=$(REQUIRE_UNITSDIR)
+endif
+ifdef REQUIRE_PACKAGESDIR
+override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR)
+endif
+ifdef ZIPINSTALL
+ifneq ($(findstring $(OS_TARGET),$(UNIXs)),)
+UNIXHier=1
+endif
+else
+ifneq ($(findstring $(OS_SOURCE),$(UNIXs)),)
+UNIXHier=1
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef PREFIX
+INSTALL_PREFIX=$(PREFIX)
+endif
+endif
+ifndef INSTALL_PREFIX
+ifdef UNIXHier
+INSTALL_PREFIX=/usr/local
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=/pp
+else
+INSTALL_BASEDIR:=/$(PACKAGE_NAME)
+endif
+endif
+endif
+export INSTALL_PREFIX
+ifdef INSTALL_FPCSUBDIR
+export INSTALL_FPCSUBDIR
+endif
+ifndef DIST_DESTDIR
+DIST_DESTDIR:=$(BASEDIR)
+endif
+export DIST_DESTDIR
+ifndef COMPILER_UNITTARGETDIR
+ifdef PACKAGEDIR_MAIN
+COMPILER_UNITTARGETDIR=$(PACKAGEDIR_MAIN)/units/$(TARGETSUFFIX)
+else
+COMPILER_UNITTARGETDIR=units/$(TARGETSUFFIX)
+endif
+endif
+ifndef COMPILER_TARGETDIR
+COMPILER_TARGETDIR=.
+endif
+ifndef INSTALL_BASEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION)
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME)
+endif
+else
+INSTALL_BASEDIR:=$(INSTALL_PREFIX)
+endif
+endif
+ifndef INSTALL_BINDIR
+ifdef UNIXHier
+INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin
+else
+INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin
+ifdef INSTALL_FPCPACKAGE
+ifdef CROSSCOMPILE
+ifdef CROSSINSTALL
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(SOURCESUFFIX)
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+else
+INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX)
+endif
+endif
+endif
+endif
+ifndef INSTALL_UNITDIR
+INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(TARGETSUFFIX)
+ifdef INSTALL_FPCPACKAGE
+ifdef PACKAGE_NAME
+INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME)
+endif
+endif
+endif
+ifndef INSTALL_LIBDIR
+ifdef UNIXHier
+INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib
+else
+INSTALL_LIBDIR:=$(INSTALL_UNITDIR)
+endif
+endif
+ifndef INSTALL_SOURCEDIR
+ifdef UNIXHier
+ifdef BSDhier
+SRCPREFIXDIR=share/src
+else
+ifdef linuxHier
+SRCPREFIXDIR=share/src
+else
+SRCPREFIXDIR=src
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+ifdef INSTALL_FPCSUBDIR
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME)
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME)
+endif
+else
+INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source
+endif
+endif
+endif
+ifndef INSTALL_DOCDIR
+ifdef UNIXHier
+ifdef BSDhier
+DOCPREFIXDIR=share/doc
+else
+ifdef linuxHier
+DOCPREFIXDIR=share/doc
+else
+DOCPREFIXDIR=doc
+endif
+endif
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME)
+else
+INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc
+endif
+endif
+endif
+ifndef INSTALL_EXAMPLEDIR
+ifdef UNIXHier
+ifdef INSTALL_FPCPACKAGE
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME)
+endif
+endif
+else
+ifdef BSDhier
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+ifdef linuxHier
+INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
+endif
+endif
+endif
+else
+ifdef INSTALL_FPCPACKAGE
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME)
+else
+INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples
+endif
+endif
+endif
+ifndef INSTALL_DATADIR
+INSTALL_DATADIR=$(INSTALL_BASEDIR)
+endif
+ifndef INSTALL_SHAREDDIR
+INSTALL_SHAREDDIR=$(INSTALL_PREFIX)/lib
+endif
+ifdef CROSSCOMPILE
+ifndef CROSSBINDIR
+CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(SOURCESUFFIX))
+ifeq ($(CROSSBINDIR),)
+CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(TARGETSUFFIX)/bin/$(FULL_SOURCE))
+endif
+endif
+else
+CROSSBINDIR=
+endif
+BATCHEXT=.bat
+LOADEREXT=.as
+EXEEXT=.exe
+PPLEXT=.ppl
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.so
+SHAREDLIBPREFIX=libfp
+STATICLIBPREFIX=libp
+IMPORTLIBPREFIX=libimp
+RSTEXT=.rst
+ifeq ($(findstring 1.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),go32v1)
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+OEXT=.obj
+ASMEXT=.asm
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=wat
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+endif
+ifeq ($(OS_TARGET),emx)
+BATCHEXT=.cmd
+AOUTEXT=.out
+STATICLIBPREFIX=
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=emx
+ECHO=echo
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),morphos)
+EXEEXT=
+SHAREDLIBEXT=.library
+SHORTSUFFIX=mos
+endif
+ifeq ($(OS_TARGET),atari)
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nw
+endif
+ifeq ($(OS_TARGET),netwlibc)
+EXEEXT=.nlm
+STATICLIBPREFIX=
+SHORTSUFFIX=nwl
+endif
+ifeq ($(OS_TARGET),macos)
+BATCHEXT=
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+endif
+ifeq ($(OS_TARGET),darwin)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=dwn
+endif
+ifeq ($(OS_TARGET),gba)
+EXEEXT=.gba
+SHAREDLIBEXT=.so
+SHORTSUFFIX=gba
+endif
+ifeq ($(OS_TARGET),symbian)
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=symbian
+endif
+else
+ifeq ($(OS_TARGET),go32v1)
+PPUEXT=.pp1
+OEXT=.o1
+ASMEXT=.s1
+SMARTEXT=.sl1
+STATICLIBEXT=.a1
+SHAREDLIBEXT=.so1
+STATICLIBPREFIX=
+SHORTSUFFIX=v1
+endif
+ifeq ($(OS_TARGET),go32v2)
+STATICLIBPREFIX=
+SHORTSUFFIX=dos
+endif
+ifeq ($(OS_TARGET),watcom)
+STATICLIBPREFIX=
+SHORTSUFFIX=wat
+endif
+ifeq ($(OS_TARGET),linux)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=lnx
+endif
+ifeq ($(OS_TARGET),freebsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=fbs
+endif
+ifeq ($(OS_TARGET),netbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=nbs
+endif
+ifeq ($(OS_TARGET),openbsd)
+BATCHEXT=.sh
+EXEEXT=
+HASSHAREDLIB=1
+SHORTSUFFIX=obs
+endif
+ifeq ($(OS_TARGET),win32)
+PPUEXT=.ppw
+OEXT=.ow
+ASMEXT=.sw
+SMARTEXT=.slw
+STATICLIBEXT=.aw
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=w32
+endif
+ifeq ($(OS_TARGET),os2)
+BATCHEXT=.cmd
+PPUEXT=.ppo
+ASMEXT=.so2
+OEXT=.oo2
+AOUTEXT=.out
+SMARTEXT=.sl2
+STATICLIBPREFIX=
+STATICLIBEXT=.ao2
+SHAREDLIBEXT=.dll
+SHORTSUFFIX=os2
+ECHO=echo
+endif
+ifeq ($(OS_TARGET),amiga)
+EXEEXT=
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.library
+SHORTSUFFIX=amg
+endif
+ifeq ($(OS_TARGET),atari)
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=.ttp
+SHORTSUFFIX=ata
+endif
+ifeq ($(OS_TARGET),beos)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=be
+endif
+ifeq ($(OS_TARGET),solaris)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=sun
+endif
+ifeq ($(OS_TARGET),qnx)
+BATCHEXT=.sh
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+SHORTSUFFIX=qnx
+endif
+ifeq ($(OS_TARGET),netware)
+STATICLIBPREFIX=
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.nlm
+EXEEXT=.nlm
+SHORTSUFFIX=nw
+endif
+ifeq ($(OS_TARGET),netwlibc)
+STATICLIBPREFIX=
+PPUEXT=.ppu
+OEXT=.o
+ASMEXT=.s
+SMARTEXT=.sl
+STATICLIBEXT=.a
+SHAREDLIBEXT=.nlm
+EXEEXT=.nlm
+SHORTSUFFIX=nwl
+endif
+ifeq ($(OS_TARGET),macos)
+BATCHEXT=
+PPUEXT=.ppu
+ASMEXT=.s
+OEXT=.o
+SMARTEXT=.sl
+STATICLIBEXT=.a
+EXEEXT=
+DEBUGSYMEXT=.xcoff
+SHORTSUFFIX=mac
+endif
+endif
+ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),)
+FPCMADE=fpcmade.$(SHORTSUFFIX)
+ZIPSUFFIX=$(SHORTSUFFIX)
+ZIPCROSSPREFIX=
+ZIPSOURCESUFFIX=src
+ZIPEXAMPLESUFFIX=exm
+else
+FPCMADE=fpcmade.$(TARGETSUFFIX)
+ZIPSOURCESUFFIX=.source
+ZIPEXAMPLESUFFIX=.examples
+ifdef CROSSCOMPILE
+ZIPSUFFIX=.$(SOURCESUFFIX)
+ZIPCROSSPREFIX=$(TARGETSUFFIX)-
+else
+ZIPSUFFIX=.$(TARGETSUFFIX)
+ZIPCROSSPREFIX=
+endif
+endif
+ifndef ECHO
+ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ECHO),)
+ECHO= __missing_command_ECHO
+else
+ECHO:=$(firstword $(ECHO))
+endif
+else
+ECHO:=$(firstword $(ECHO))
+endif
+endif
+export ECHO
+ifndef DATE
+DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(DATE),)
+DATE= __missing_command_DATE
+else
+DATE:=$(firstword $(DATE))
+endif
+else
+DATE:=$(firstword $(DATE))
+endif
+endif
+export DATE
+ifndef GINSTALL
+GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(GINSTALL),)
+GINSTALL= __missing_command_GINSTALL
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+else
+GINSTALL:=$(firstword $(GINSTALL))
+endif
+endif
+export GINSTALL
+ifndef CPPROG
+CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(CPPROG),)
+CPPROG= __missing_command_CPPROG
+else
+CPPROG:=$(firstword $(CPPROG))
+endif
+endif
+export CPPROG
+ifndef RMPROG
+RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(RMPROG),)
+RMPROG= __missing_command_RMPROG
+else
+RMPROG:=$(firstword $(RMPROG))
+endif
+endif
+export RMPROG
+ifndef MVPROG
+MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MVPROG),)
+MVPROG= __missing_command_MVPROG
+else
+MVPROG:=$(firstword $(MVPROG))
+endif
+endif
+export MVPROG
+ifndef MKDIRPROG
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /gmkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG:=$(strip $(wildcard $(addsuffix /mkdir$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(MKDIRPROG),)
+MKDIRPROG= __missing_command_MKDIRPROG
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+else
+MKDIRPROG:=$(firstword $(MKDIRPROG))
+endif
+endif
+export MKDIRPROG
+ifndef ECHOREDIR
+ifndef inUnix
+ECHOREDIR=echo
+else
+ECHOREDIR=$(ECHO)
+endif
+endif
+ifndef COPY
+COPY:=$(CPPROG) -fp
+endif
+ifndef COPYTREE
+COPYTREE:=$(CPPROG) -Rfp
+endif
+ifndef MKDIRTREE
+MKDIRTREE:=$(MKDIRPROG) -p
+endif
+ifndef MOVE
+MOVE:=$(MVPROG) -f
+endif
+ifndef DEL
+DEL:=$(RMPROG) -f
+endif
+ifndef DELTREE
+DELTREE:=$(RMPROG) -rf
+endif
+ifndef INSTALL
+ifdef inUnix
+INSTALL:=$(GINSTALL) -c -m 644
+else
+INSTALL:=$(COPY)
+endif
+endif
+ifndef INSTALLEXE
+ifdef inUnix
+INSTALLEXE:=$(GINSTALL) -c -m 755
+else
+INSTALLEXE:=$(COPY)
+endif
+endif
+ifndef MKDIR
+MKDIR:=$(GINSTALL) -m 755 -d
+endif
+export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR
+ifndef PPUMOVE
+PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(PPUMOVE),)
+PPUMOVE= __missing_command_PPUMOVE
+else
+PPUMOVE:=$(firstword $(PPUMOVE))
+endif
+endif
+export PPUMOVE
+ifndef FPCMAKE
+FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(FPCMAKE),)
+FPCMAKE= __missing_command_FPCMAKE
+else
+FPCMAKE:=$(firstword $(FPCMAKE))
+endif
+endif
+export FPCMAKE
+ifndef ZIPPROG
+ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(ZIPPROG),)
+ZIPPROG= __missing_command_ZIPPROG
+else
+ZIPPROG:=$(firstword $(ZIPPROG))
+endif
+endif
+export ZIPPROG
+ifndef TARPROG
+TARPROG:=$(strip $(wildcard $(addsuffix /gtar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(TARPROG),)
+TARPROG= __missing_command_TARPROG
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+else
+TARPROG:=$(firstword $(TARPROG))
+endif
+endif
+export TARPROG
+ASNAME=$(BINUTILSPREFIX)as
+LDNAME=$(BINUTILSPREFIX)ld
+ARNAME=$(BINUTILSPREFIX)ar
+RCNAME=$(BINUTILSPREFIX)rc
+ifneq ($(findstring 1.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),win32)
+ifeq ($(CROSSBINDIR),)
+ASNAME=asw
+LDNAME=ldw
+ARNAME=arw
+endif
+endif
+endif
+ifndef ASPROG
+ifdef CROSSBINDIR
+ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT)
+else
+ASPROG=$(ASNAME)
+endif
+endif
+ifndef LDPROG
+ifdef CROSSBINDIR
+LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT)
+else
+LDPROG=$(LDNAME)
+endif
+endif
+ifndef RCPROG
+ifdef CROSSBINDIR
+RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT)
+else
+RCPROG=$(RCNAME)
+endif
+endif
+ifndef ARPROG
+ifdef CROSSBINDIR
+ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT)
+else
+ARPROG=$(ARNAME)
+endif
+endif
+AS=$(ASPROG)
+LD=$(LDPROG)
+RC=$(RCPROG)
+AR=$(ARPROG)
+PPAS=ppas$(SRCBATCHEXT)
+ifdef inUnix
+LDCONFIG=ldconfig
+else
+LDCONFIG=
+endif
+ifdef DATE
+DATESTR:=$(shell $(DATE) +%Y%m%d)
+else
+DATESTR=
+endif
+ifndef UPXPROG
+ifeq ($(OS_TARGET),go32v2)
+UPXPROG:=1
+endif
+ifeq ($(OS_TARGET),win32)
+UPXPROG:=1
+endif
+ifdef UPXPROG
+UPXPROG:=$(strip $(wildcard $(addsuffix /upx$(SRCEXEEXT),$(SEARCHPATH))))
+ifeq ($(UPXPROG),)
+UPXPROG=
+else
+UPXPROG:=$(firstword $(UPXPROG))
+endif
+else
+UPXPROG=
+endif
+endif
+export UPXPROG
+ZIPOPT=-9
+ZIPEXT=.zip
+ifeq ($(USETAR),bz2)
+TAROPT=vj
+TAREXT=.tar.bz2
+else
+TAROPT=vz
+TAREXT=.tar.gz
+endif
+override REQUIRE_PACKAGES=rtl 
+ifeq ($(FULL_TARGET),i386-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-go32v2)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-win32)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-os2)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-beos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-solaris)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-qnx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netware)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-openbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-wdosx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-emx)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-watcom)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-netwlibc)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-wince)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),i386-symbian)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-amiga)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-atari)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-openbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-palmos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),m68k-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-amiga)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-macos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-morphos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-netbsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-solaris)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),sparc-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-freebsd)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-win64)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),x86_64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-palmos)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-wince)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-gba)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-nds)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),arm-symbian)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-linux)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-darwin)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),powerpc64-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifdef REQUIRE_PACKAGES_RTL
+PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
+ifneq ($(PACKAGEDIR_RTL),)
+ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)),)
+UNITDIR_RTL=$(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)
+else
+UNITDIR_RTL=$(PACKAGEDIR_RTL)
+endif
+ifdef CHECKDEPEND
+$(PACKAGEDIR_RTL)/$(FPCMADE):
+	$(MAKE) -C $(PACKAGEDIR_RTL) $(FPCMADE)
+override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(FPCMADE)
+endif
+else
+PACKAGEDIR_RTL=
+UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR)))))
+ifneq ($(UNITDIR_RTL),)
+UNITDIR_RTL:=$(firstword $(UNITDIR_RTL))
+else
+UNITDIR_RTL=
+endif
+endif
+ifdef UNITDIR_RTL
+override COMPILER_UNITDIR+=$(UNITDIR_RTL)
+endif
+endif
+ifndef NOCPUDEF
+override FPCOPTDEF=$(CPU_TARGET)
+endif
+ifneq ($(OS_TARGET),$(OS_SOURCE))
+override FPCOPT+=-T$(OS_TARGET)
+endif
+ifneq ($(CPU_TARGET),$(CPU_SOURCE))
+override FPCOPT+=-P$(CPU_TARGET)
+endif
+ifeq ($(OS_SOURCE),openbsd)
+override FPCOPT+=-FD$(NEW_BINUTILS_PATH)
+endif
+ifndef CROSSBOOTSTRAP
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-XP$(BINUTILSPREFIX)
+endif
+ifneq ($(BINUTILSPREFIX),)
+override FPCOPT+=-Xr$(RLINKPATH)
+endif
+endif
+ifdef UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(UNITDIR))
+endif
+ifdef LIBDIR
+override FPCOPT+=$(addprefix -Fl,$(LIBDIR))
+endif
+ifdef OBJDIR
+override FPCOPT+=$(addprefix -Fo,$(OBJDIR))
+endif
+ifdef INCDIR
+override FPCOPT+=$(addprefix -Fi,$(INCDIR))
+endif
+ifdef LINKSMART
+override FPCOPT+=-XX
+endif
+ifdef CREATESMART
+override FPCOPT+=-CX
+endif
+ifdef DEBUG
+override FPCOPT+=-gl
+override FPCOPTDEF+=DEBUG
+endif
+ifdef RELEASE
+ifneq ($(findstring 2.0.,$(FPC_VERSION)),)
+ifeq ($(CPU_TARGET),i386)
+FPCCPUOPT:=-OG2p3
+endif
+ifeq ($(CPU_TARGET),powerpc)
+FPCCPUOPT:=-O1r
+endif
+else
+FPCCPUOPT:=-O2
+endif
+override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n
+override FPCOPTDEF+=RELEASE
+endif
+ifdef STRIP
+override FPCOPT+=-Xs
+endif
+ifdef OPTIMIZE
+override FPCOPT+=-O2
+endif
+ifdef VERBOSE
+override FPCOPT+=-vwni
+endif
+ifdef COMPILER_OPTIONS
+override FPCOPT+=$(COMPILER_OPTIONS)
+endif
+ifdef COMPILER_UNITDIR
+override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR))
+endif
+ifdef COMPILER_LIBRARYDIR
+override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR))
+endif
+ifdef COMPILER_OBJECTDIR
+override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR))
+endif
+ifdef COMPILER_INCLUDEDIR
+override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR))
+endif
+ifdef CROSSBINDIR
+override FPCOPT+=-FD$(CROSSBINDIR)
+endif
+ifdef COMPILER_TARGETDIR
+override FPCOPT+=-FE$(COMPILER_TARGETDIR)
+ifeq ($(COMPILER_TARGETDIR),.)
+override TARGETDIRPREFIX=
+else
+override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/
+endif
+endif
+ifdef COMPILER_UNITTARGETDIR
+override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR)
+ifeq ($(COMPILER_UNITTARGETDIR),.)
+override UNITTARGETDIRPREFIX=
+else
+override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/
+endif
+else
+ifdef COMPILER_TARGETDIR
+override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR)
+override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX)
+endif
+endif
+ifdef CREATESHARED
+override FPCOPT+=-Cg
+ifeq ($(CPU_TARGET),i386)
+override FPCOPT+=-Aas
+endif
+endif
+ifeq ($(findstring 2.0.,$(FPC_VERSION)),)
+ifeq ($(OS_TARGET),linux)
+ifeq ($(CPU_TARGET),x86_64)
+override FPCOPT+=-Cg
+endif
+endif
+endif
+ifdef LINKSHARED
+endif
+ifdef OPT
+override FPCOPT+=$(OPT)
+endif
+ifdef FPCOPTDEF
+override FPCOPT+=$(addprefix -d,$(FPCOPTDEF))
+endif
+ifdef CFGFILE
+override FPCOPT+=@$(CFGFILE)
+endif
+ifdef USEENV
+override FPCEXTCMD:=$(FPCOPT)
+override FPCOPT:=!FPCEXTCMD
+export FPCEXTCMD
+endif
+override AFULL_TARGET=$(CPU_TARGET)-$(OS_TARGET)
+override AFULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE)
+ifneq ($(AFULL_TARGET),$(AFULL_SOURCE))
+override ACROSSCOMPILE=1
+endif
+ifdef ACROSSCOMPILE
+override FPCOPT+=$(CROSSOPT)
+endif
+override COMPILER:=$(FPC) $(FPCOPT)
+ifeq (,$(findstring -s ,$(COMPILER)))
+EXECPPAS=
+else
+ifeq ($(FULL_SOURCE),$(FULL_TARGET))
+ifdef RUNBATCH
+EXECPPAS:=@$(RUNBATCH) $(PPAS)
+else
+EXECPPAS:=@$(PPAS)
+endif
+endif
+endif
+.PHONY: fpc_units
+ifneq ($(TARGET_UNITS),)
+override ALLTARGET+=fpc_units
+override UNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_UNITS))
+override IMPLICITUNITPPUFILES=$(addsuffix $(PPUEXT),$(TARGET_IMPLICITUNITS))
+override INSTALLPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES)
+override CLEANPPUFILES+=$(UNITPPUFILES) $(IMPLICITUNITPPUFILES)
+endif
+fpc_units: $(COMPILER_UNITTARGETDIR) $(UNITPPUFILES)
+ifdef TARGET_RSTS
+override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS))
+override CLEANRSTFILES+=$(RSTFILES)
+endif
+.PHONY: fpc_all fpc_smart fpc_debug fpc_release fpc_shared
+$(FPCMADE): $(ALLDEPENDENCIES) $(ALLTARGET)
+	@$(ECHOREDIR) Compiled > $(FPCMADE)
+fpc_all: $(FPCMADE)
+fpc_smart:
+	$(MAKE) all LINKSMART=1 CREATESMART=1
+fpc_debug:
+	$(MAKE) all DEBUG=1
+fpc_release:
+	$(MAKE) all RELEASE=1
+.SUFFIXES: $(EXEEXT) $(PPUEXT) $(OEXT) .pas .lpr .dpr .pp .rc .res
+$(COMPILER_UNITTARGETDIR):
+	$(MKDIRTREE) $(COMPILER_UNITTARGETDIR)
+$(COMPILER_TARGETDIR):
+	$(MKDIRTREE) $(COMPILER_TARGETDIR)
+%$(PPUEXT): %.pp
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(PPUEXT): %.pas
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.pp
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.pas
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.lpr
+	$(COMPILER) $<
+	$(EXECPPAS)
+%$(EXEEXT): %.dpr
+	$(COMPILER) $<
+	$(EXECPPAS)
+%.res: %.rc
+	windres -i $< -o $@
+vpath %.pp $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.pas $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.lpr $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.dpr $(COMPILER_SOURCEDIR) $(COMPILER_INCLUDEDIR)
+vpath %.inc $(COMPILER_INCLUDEDIR)
+vpath %$(OEXT) $(COMPILER_UNITTARGETDIR)
+vpath %$(PPUEXT) $(COMPILER_UNITTARGETDIR)
+.PHONY: fpc_shared
+override INSTALLTARGET+=fpc_shared_install
+ifndef SHARED_LIBVERSION
+SHARED_LIBVERSION=$(FPC_VERSION)
+endif
+ifndef SHARED_LIBNAME
+SHARED_LIBNAME=$(PACKAGE_NAME)
+endif
+ifndef SHARED_FULLNAME
+SHARED_FULLNAME=$(SHAREDLIBPREFIX)$(SHARED_LIBNAME)-$(SHARED_LIBVERSION)$(SHAREDLIBEXT)
+endif
+ifndef SHARED_LIBUNITS
+SHARED_LIBUNITS:=$(TARGET_UNITS) $(TARGET_IMPLICITUNITS)
+override SHARED_LIBUNITS:=$(filter-out $(INSTALL_BUILDUNIT),$(SHARED_LIBUNITS))
+endif
+fpc_shared:
+ifdef HASSHAREDLIB
+	$(MAKE) all CREATESHARED=1 LINKSHARED=1 CREATESMART=1
+ifneq ($(SHARED_BUILD),n)
+	$(PPUMOVE) -q $(SHARED_LIBUNITS) -i$(COMPILER_UNITTARGETDIR) -o$(SHARED_FULLNAME) -d$(COMPILER_UNITTARGETDIR)
+endif
+else
+	@$(ECHO) Shared Libraries not supported
+endif
+fpc_shared_install:
+ifneq ($(SHARED_BUILD),n)
+ifneq ($(SHARED_LIBUNITS),)
+ifneq ($(wildcard $(COMPILER_UNITTARGETDIR)/$(SHARED_FULLNAME)),)
+	$(INSTALL) $(COMPILER_UNITTARGETDIR)/$(SHARED_FULLNAME) $(INSTALL_SHAREDDIR)
+endif
+endif
+endif
+.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall
+ifdef INSTALL_UNITS
+override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS))
+endif
+ifdef INSTALL_BUILDUNIT
+override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES))
+endif
+ifdef INSTALLPPUFILES
+override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES)))
+ifneq ($(UNITTARGETDIRPREFIX),)
+override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPUFILES)))
+override INSTALLPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPULINKFILES))))
+endif
+override INSTALL_CREATEPACKAGEFPC=1
+endif
+ifdef INSTALLEXEFILES
+ifneq ($(TARGETDIRPREFIX),)
+override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(notdir $(INSTALLEXEFILES)))
+endif
+endif
+fpc_install: all $(INSTALLTARGET)
+ifdef INSTALLEXEFILES
+	$(MKDIR) $(INSTALL_BINDIR)
+ifdef UPXPROG
+	-$(UPXPROG) $(INSTALLEXEFILES)
+endif
+	$(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR)
+endif
+ifdef INSTALL_CREATEPACKAGEFPC
+ifdef FPCMAKE
+ifdef PACKAGE_VERSION
+ifneq ($(wildcard Makefile.fpc),)
+	$(FPCMAKE) -p -T$(CPU_TARGET)-$(OS_TARGET) Makefile.fpc
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) Package.fpc $(INSTALL_UNITDIR)
+endif
+endif
+endif
+endif
+ifdef INSTALLPPUFILES
+	$(MKDIR) $(INSTALL_UNITDIR)
+	$(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR)
+ifneq ($(INSTALLPPULINKFILES),)
+	$(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR)
+endif
+ifneq ($(wildcard $(LIB_FULLNAME)),)
+	$(MKDIR) $(INSTALL_LIBDIR)
+	$(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR)
+ifdef inUnix
+	ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME)
+endif
+endif
+endif
+ifdef INSTALL_FILES
+	$(MKDIR) $(INSTALL_DATADIR)
+	$(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR)
+endif
+fpc_sourceinstall: distclean
+	$(MKDIR) $(INSTALL_SOURCEDIR)
+	$(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR)
+fpc_exampleinstall: $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS))
+ifdef HASEXAMPLES
+	$(MKDIR) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef EXAMPLESOURCEFILES
+	$(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR)
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR)
+endif
+.PHONY: fpc_distinstall
+fpc_distinstall: install exampleinstall
+.PHONY: fpc_zipinstall fpc_zipsourceinstall fpc_zipexampleinstall
+ifndef PACKDIR
+ifndef inUnix
+PACKDIR=$(BASEDIR)/../fpc-pack
+else
+PACKDIR=/tmp/fpc-pack
+endif
+endif
+ifndef ZIPNAME
+ifdef DIST_ZIPNAME
+ZIPNAME=$(DIST_ZIPNAME)
+else
+ZIPNAME=$(PACKAGE_NAME)
+endif
+endif
+ifndef FULLZIPNAME
+FULLZIPNAME=$(ZIPCROSSPREFIX)$(ZIPPREFIX)$(ZIPNAME)$(ZIPSUFFIX)
+endif
+ifndef ZIPTARGET
+ifdef DIST_ZIPTARGET
+ZIPTARGET=DIST_ZIPTARGET
+else
+ZIPTARGET=install
+endif
+endif
+ifndef USEZIP
+ifdef inUnix
+USETAR=1
+endif
+endif
+ifndef inUnix
+USEZIPWRAPPER=1
+endif
+ifdef USEZIPWRAPPER
+ZIPPATHSEP=$(PATHSEP)
+ZIPWRAPPER=$(subst /,$(PATHSEP),$(DIST_DESTDIR)/fpczip$(SRCBATCHEXT))
+else
+ZIPPATHSEP=/
+endif
+ZIPCMD_CDPACK:=cd $(subst /,$(ZIPPATHSEP),$(PACKDIR))
+ZIPCMD_CDBASE:=cd $(subst /,$(ZIPPATHSEP),$(BASEDIR))
+ifdef USETAR
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(TAREXT)
+ZIPCMD_ZIP:=$(TARPROG) cf$(TAROPT) $(ZIPDESTFILE) *
+else
+ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(ZIPEXT)
+ZIPCMD_ZIP:=$(subst /,$(ZIPPATHSEP),$(ZIPPROG)) -Dr $(ZIPOPT) $(ZIPDESTFILE) *
+endif
+fpc_zipinstall:
+	$(MAKE) $(ZIPTARGET) INSTALL_PREFIX=$(PACKDIR) ZIPINSTALL=1
+	$(MKDIR) $(DIST_DESTDIR)
+	$(DEL) $(ZIPDESTFILE)
+ifdef USEZIPWRAPPER
+ifneq ($(ECHOREDIR),echo)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDPACK))" > $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_ZIP))" >> $(ZIPWRAPPER)
+	$(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDBASE))" >> $(ZIPWRAPPER)
+else
+	echo $(ZIPCMD_CDPACK) > $(ZIPWRAPPER)
+	echo $(ZIPCMD_ZIP) >> $(ZIPWRAPPER)
+	echo $(ZIPCMD_CDBASE) >> $(ZIPWRAPPER)
+endif
+ifdef inUnix
+	/bin/sh $(ZIPWRAPPER)
+else
+ifdef RUNBATCH
+	$(RUNBATCH) (ZIPWRAPPER)
+else
+	$(ZIPWRAPPER)
+endif
+endif
+	$(DEL) $(ZIPWRAPPER)
+else
+	$(ZIPCMD_CDPACK) ; $(ZIPCMD_ZIP) ; $(ZIPCMD_CDBASE)
+endif
+	$(DELTREE) $(PACKDIR)
+fpc_zipsourceinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall ZIPSUFFIX=$(ZIPSOURCESUFFIX)
+fpc_zipexampleinstall:
+ifdef HASEXAMPLES
+	$(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall ZIPSUFFIX=$(ZIPEXAMPLESUFFIX)
+endif
+fpc_zipdistinstall:
+	$(MAKE) fpc_zipinstall ZIPTARGET=distinstall
+.PHONY: fpc_clean fpc_cleanall fpc_distclean
+ifdef EXEFILES
+override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES))
+endif
+ifdef CLEAN_UNITS
+override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS))
+endif
+ifdef CLEANPPUFILES
+override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES)))
+ifdef DEBUGSYMEXT
+override CLEANPPULINKFILES+=$(subst $(PPUEXT),$(DEBUGSYMEXT),$(CLEANPPUFILES))
+endif
+override CLEANPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILES))
+override CLEANPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILES)))
+endif
+fpc_clean: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+ifdef CLEAN_FILES
+	-$(DEL) $(CLEAN_FILES)
+endif
+ifdef LIB_NAME
+	-$(DEL) $(LIB_NAME) $(LIB_FULLNAME)
+endif
+	-$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *$(ASMEXT) *_ppas$(BATCHEXT)
+fpc_cleanall: $(CLEANTARGET)
+ifdef CLEANEXEFILES
+	-$(DEL) $(CLEANEXEFILES)
+endif
+ifdef COMPILER_UNITTARGETDIR
+ifdef CLEANPPUFILES
+	-$(DEL) $(CLEANPPUFILES)
+endif
+ifneq ($(CLEANPPULINKFILES),)
+	-$(DEL) $(CLEANPPULINKFILES)
+endif
+ifdef CLEANRSTFILES
+	-$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES))
+endif
+endif
+	-$(DELTREE) units
+	-$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)
+ifneq ($(PPUEXT),.ppu)
+	-$(DEL) *.o *.ppu *.a
+endif
+	-$(DELTREE) *$(SMARTEXT)
+	-$(DEL) fpcmade.* Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE)
+	-$(DEL) *_ppas$(BATCHEXT)
+ifdef AOUTEXT
+	-$(DEL) *$(AOUTEXT)
+endif
+ifdef DEBUGSYMEXT
+	-$(DEL) *$(DEBUGSYMEXT)
+endif
+fpc_distclean: cleanall
+.PHONY: fpc_baseinfo
+override INFORULES+=fpc_baseinfo
+fpc_baseinfo:
+	@$(ECHO)
+	@$(ECHO)  == Package info ==
+	@$(ECHO)  Package Name..... $(PACKAGE_NAME)
+	@$(ECHO)  Package Version.. $(PACKAGE_VERSION)
+	@$(ECHO)
+	@$(ECHO)  == Configuration info ==
+	@$(ECHO)
+	@$(ECHO)  FPC.......... $(FPC)
+	@$(ECHO)  FPC Version.. $(FPC_VERSION)
+	@$(ECHO)  Source CPU... $(CPU_SOURCE)
+	@$(ECHO)  Target CPU... $(CPU_TARGET)
+	@$(ECHO)  Source OS.... $(OS_SOURCE)
+	@$(ECHO)  Target OS.... $(OS_TARGET)
+	@$(ECHO)  Full Source.. $(FULL_SOURCE)
+	@$(ECHO)  Full Target.. $(FULL_TARGET)
+	@$(ECHO)  SourceSuffix. $(SOURCESUFFIX)
+	@$(ECHO)  TargetSuffix. $(TARGETSUFFIX)
+	@$(ECHO)
+	@$(ECHO)  == Directory info ==
+	@$(ECHO)
+	@$(ECHO)  Required pkgs... $(REQUIRE_PACKAGES)
+	@$(ECHO)
+	@$(ECHO)  Basedir......... $(BASEDIR)
+	@$(ECHO)  FPCDir.......... $(FPCDIR)
+	@$(ECHO)  CrossBinDir..... $(CROSSBINDIR)
+	@$(ECHO)  UnitsDir........ $(UNITSDIR)
+	@$(ECHO)  PackagesDir..... $(PACKAGESDIR)
+	@$(ECHO)
+	@$(ECHO)  GCC library..... $(GCCLIBDIR)
+	@$(ECHO)  Other library... $(OTHERLIBDIR)
+	@$(ECHO)
+	@$(ECHO)  == Tools info ==
+	@$(ECHO)
+	@$(ECHO)  As........ $(AS)
+	@$(ECHO)  Ld........ $(LD)
+	@$(ECHO)  Ar........ $(AR)
+	@$(ECHO)  Rc........ $(RC)
+	@$(ECHO)
+	@$(ECHO)  Mv........ $(MVPROG)
+	@$(ECHO)  Cp........ $(CPPROG)
+	@$(ECHO)  Rm........ $(RMPROG)
+	@$(ECHO)  GInstall.. $(GINSTALL)
+	@$(ECHO)  Echo...... $(ECHO)
+	@$(ECHO)  Shell..... $(SHELL)
+	@$(ECHO)  Date...... $(DATE)
+	@$(ECHO)  FPCMake... $(FPCMAKE)
+	@$(ECHO)  PPUMove... $(PPUMOVE)
+	@$(ECHO)  Upx....... $(UPXPROG)
+	@$(ECHO)  Zip....... $(ZIPPROG)
+	@$(ECHO)
+	@$(ECHO)  == Object info ==
+	@$(ECHO)
+	@$(ECHO)  Target Loaders........ $(TARGET_LOADERS)
+	@$(ECHO)  Target Units.......... $(TARGET_UNITS)
+	@$(ECHO)  Target Implicit Units. $(TARGET_IMPLICITUNITS)
+	@$(ECHO)  Target Programs....... $(TARGET_PROGRAMS)
+	@$(ECHO)  Target Dirs........... $(TARGET_DIRS)
+	@$(ECHO)  Target Examples....... $(TARGET_EXAMPLES)
+	@$(ECHO)  Target ExampleDirs.... $(TARGET_EXAMPLEDIRS)
+	@$(ECHO)
+	@$(ECHO)  Clean Units......... $(CLEAN_UNITS)
+	@$(ECHO)  Clean Files......... $(CLEAN_FILES)
+	@$(ECHO)
+	@$(ECHO)  Install Units....... $(INSTALL_UNITS)
+	@$(ECHO)  Install Files....... $(INSTALL_FILES)
+	@$(ECHO)
+	@$(ECHO)  == Install info ==
+	@$(ECHO)
+	@$(ECHO)  DateStr.............. $(DATESTR)
+	@$(ECHO)  ZipName.............. $(ZIPNAME)
+	@$(ECHO)  ZipPrefix............ $(ZIPPREFIX)
+	@$(ECHO)  ZipCrossPrefix....... $(ZIPCROSSPREFIX)
+	@$(ECHO)  ZipSuffix............ $(ZIPSUFFIX)
+	@$(ECHO)  FullZipName.......... $(FULLZIPNAME)
+	@$(ECHO)  Install FPC Package.. $(INSTALL_FPCPACKAGE)
+	@$(ECHO)
+	@$(ECHO)  Install base dir..... $(INSTALL_BASEDIR)
+	@$(ECHO)  Install binary dir... $(INSTALL_BINDIR)
+	@$(ECHO)  Install library dir.. $(INSTALL_LIBDIR)
+	@$(ECHO)  Install units dir.... $(INSTALL_UNITDIR)
+	@$(ECHO)  Install source dir... $(INSTALL_SOURCEDIR)
+	@$(ECHO)  Install doc dir...... $(INSTALL_DOCDIR)
+	@$(ECHO)  Install example dir.. $(INSTALL_EXAMPLEDIR)
+	@$(ECHO)  Install data dir..... $(INSTALL_DATADIR)
+	@$(ECHO)
+	@$(ECHO)  Dist destination dir. $(DIST_DESTDIR)
+	@$(ECHO)  Dist zip name........ $(DIST_ZIPNAME)
+	@$(ECHO)
+.PHONY: fpc_info
+fpc_info: $(INFORULES)
+.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \
+	fpc_makefile_dirs
+fpc_makefile:
+	$(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc
+fpc_makefile_sub1:
+ifdef TARGET_DIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS))
+endif
+ifdef TARGET_EXAMPLEDIRS
+	$(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS))
+endif
+fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS))
+fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2
+fpc_makefiles: fpc_makefile fpc_makefile_dirs
+all: fpc_all
+debug: fpc_debug
+smart: fpc_smart
+release: fpc_release
+units: fpc_units
+examples:
+shared: fpc_shared
+install: fpc_install
+sourceinstall: fpc_sourceinstall
+exampleinstall: fpc_exampleinstall
+distinstall: fpc_distinstall
+zipinstall: fpc_zipinstall
+zipsourceinstall: fpc_zipsourceinstall
+zipexampleinstall: fpc_zipexampleinstall
+zipdistinstall: fpc_zipdistinstall
+clean: fpc_clean
+distclean: fpc_distclean
+cleanall: fpc_cleanall
+info: fpc_info
+makefiles: fpc_makefiles
+.PHONY: all debug smart release units examples shared install sourceinstall exampleinstall distinstall zipinstall zipsourceinstall zipexampleinstall zipdistinstall clean distclean cleanall info makefiles
+ifneq ($(wildcard fpcmake.loc),)
+include fpcmake.loc
+endif
+.NOTPARALLEL:

+ 31 - 0
packages/fcl-res/Makefile.fpc

@@ -0,0 +1,31 @@
+#
+#   Makefile.fpc for FCL Pascal source file parsing and writing units
+#
+
+[package]
+name=fcl-res
+version=2.2.0
+
+[target]
+units=acceleratorsresource bitmapresource coffconsts coffreader cofftypes \
+      coffwriter dfmreader elfconsts elfreader elftypes elfwriter externalreader \
+      externaltypes externalwriter fpcrestypes groupcursorresource groupiconresource \
+      groupresource icocurtypes machoconsts machoreader machotypes machowriter \
+      resdatastream resfactory resmerger resource resourcetree resreader reswriter \
+      stringtableresource strtable versionconsts versionresource versiontypes \
+      winpeimagereader
+rsts=versiontypes stringtableresource resource resfactory
+
+
+[compiler]
+options=-S2h
+sourcedir=src
+
+[install]
+fpcpackage=y
+
+[default]
+fpcdir=../..
+
+[rules]
+.NOTPARALLEL:

+ 240 - 0
packages/fcl-res/src/acceleratorsresource.pp

@@ -0,0 +1,240 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Accelerator table resource type
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit acceleratorsresource;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+
+const
+  FVirtKey  =  1;
+  FNoInvert =  2;
+  FShift    =  4;
+  FControl  =  8;
+  FAlt      = 16;
+
+type
+  TAccelerator = packed record
+    Flags : word;
+    Ansi : word;
+    Id : word;
+    padding : word;
+  end;
+  PAccelerator = ^TAccelerator;
+  
+type
+
+  { TAcceleratorsResource }
+
+  TAcceleratorsResource = class(TAbstractResource)
+  private
+    fType : TResourceDesc;
+    fName : TResourceDesc;
+    fList : TFPList;
+    procedure CheckDataLoaded;
+    function GetCount : integer;
+    function GetItem(index : integer) : TAccelerator;
+    procedure SetItem(index : integer; aAccelerator : TAccelerator);
+  protected
+    function GetType : TResourceDesc; override;
+    function GetName : TResourceDesc; override;
+    function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
+    function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
+    procedure NotifyResourcesLoaded; override;
+  public
+    constructor Create; override;
+    constructor Create(aType,aName : TResourceDesc); override;
+    destructor Destroy; override;
+    procedure UpdateRawData; override;
+    procedure Add(aItem : TAccelerator);
+    procedure Clear;
+    procedure Delete(aIndex : integer);
+    property Count : integer read GetCount;
+    property Items[index : integer] : TAccelerator read GetItem write SetItem; default;
+  end;
+
+
+implementation
+
+uses
+  resfactory;
+
+{ TAcceleratorsResource }
+
+procedure TAcceleratorsResource.CheckDataLoaded;
+var acc : TAccelerator;
+    tot, i : integer;
+    p : PAccelerator;
+begin
+  if fList<>nil then exit;
+  fList:=TFPList.Create;
+  if RawData.Size=0 then exit;
+  RawData.Position:=0;
+  tot:=RawData.Size div 8;
+  for i:=1 to tot do
+  begin
+    RawData.ReadBuffer(acc,sizeof(acc));
+    {$IFDEF ENDIAN_BIG}
+    acc.Flags:=SwapEndian(acc.Flags);
+    acc.Ansi:=SwapEndian(acc.Ansi);
+    acc.Id:=SwapEndian(acc.Id);
+    acc.padding:=SwapEndian(acc.padding);
+    {$ENDIF}
+    GetMem(p,sizeof(TAccelerator));
+    p^:=acc;
+    fList.Add(p);
+  end;
+end;
+
+function TAcceleratorsResource.GetCount: integer;
+begin
+  CheckDataLoaded;
+  Result:=fList.Count;
+end;
+
+function TAcceleratorsResource.GetItem(index: integer): TAccelerator;
+begin
+  CheckDataLoaded;
+  Result:=PAccelerator(fList[index])^;
+end;
+
+procedure TAcceleratorsResource.SetItem(index: integer;
+  aAccelerator: TAccelerator);
+begin
+  CheckDataLoaded;
+  PAccelerator(fList[index])^:=aAccelerator;
+end;
+
+function TAcceleratorsResource.GetType: TResourceDesc;
+begin
+  Result:=fType;
+end;
+
+function TAcceleratorsResource.GetName: TResourceDesc;
+begin
+  Result:=fName;
+end;
+
+function TAcceleratorsResource.ChangeDescTypeAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+function TAcceleratorsResource.ChangeDescValueAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+procedure TAcceleratorsResource.NotifyResourcesLoaded;
+begin
+end;
+
+constructor TAcceleratorsResource.Create;
+begin
+  inherited Create;
+  fList:=nil;
+  fType:=TResourceDesc.Create(RT_ACCELERATOR);
+  fName:=TResourceDesc.Create(1);
+  SetDescOwner(fType);
+  SetDescOwner(fName);
+end;
+
+constructor TAcceleratorsResource.Create(aType, aName: TResourceDesc);
+begin
+  Create;
+  fName.Assign(aName);
+end;
+
+destructor TAcceleratorsResource.Destroy;
+begin
+  fType.Free;
+  fName.Free;
+  if fList<>nil then
+  begin
+    Clear;
+    fList.Free;
+  end;
+  inherited Destroy;
+end;
+
+procedure TAcceleratorsResource.UpdateRawData;
+var acc : TAccelerator;
+    i : integer;
+begin
+  if fList=nil then exit;
+  RawData.Size:=0;
+  RawData.Position:=0;
+
+  if fList.Count>0 then
+    for i:=0 to fList.Count-1 do
+    begin
+      acc:=PAccelerator(fList[i])^;
+      // $80 means 'this is the last entry', so be sure only the last one has this bit set.
+      if i=Count-1 then acc.Flags:=acc.Flags or $80
+      else acc.Flags:=acc.Flags and $7F;
+      
+      {$IFDEF ENDIAN_BIG}
+      acc.Flags:=SwapEndian(acc.Flags);
+      acc.Ansi:=SwapEndian(acc.Ansi);
+      acc.Id:=SwapEndian(acc.Id);
+      acc.padding:=SwapEndian(acc.padding);
+      {$ENDIF}
+      RawData.WriteBuffer(acc,sizeof(acc));
+    end;
+  Clear;
+  FreeAndNil(fList);
+end;
+
+procedure TAcceleratorsResource.Add(aItem: TAccelerator);
+var p : PAccelerator;
+begin
+  CheckDataLoaded;
+  GetMem(p,sizeof(TAccelerator));
+  p^:=aItem;
+  fList.Add(p);
+end;
+
+procedure TAcceleratorsResource.Clear;
+var p : PAccelerator;
+    i : integer;
+begin
+  CheckDataLoaded;
+  for i:=0 to fList.Count-1 do
+  begin
+    p:=PAccelerator(fList[i]);
+    FreeMem(p);
+  end;
+  fList.Clear;
+end;
+
+procedure TAcceleratorsResource.Delete(aIndex: integer);
+var p : PAccelerator;
+begin
+  CheckDataLoaded;
+  p:=PAccelerator(fList[aIndex]);
+  FreeMem(p);
+  fList.Delete(aIndex);
+end;
+
+initialization
+  TResourceFactory.RegisterResourceClass(RT_ACCELERATOR,TAcceleratorsResource);
+
+end.

+ 261 - 0
packages/fcl-res/src/bitmapresource.pp

@@ -0,0 +1,261 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Bitmap resource type
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit bitmapresource;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+
+type
+
+  { TBitmapResource }
+
+  TBitmapResource = class(TAbstractResource)
+  private
+    fType : TResourceDesc;
+    fName : TResourceDesc;
+    fBitmapData : TStream;
+    function GetBitmapData : TStream;
+  protected
+    function GetType : TResourceDesc; override;
+    function GetName : TResourceDesc; override;
+    function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
+    function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
+    procedure NotifyResourcesLoaded; override;
+  public
+    constructor Create; override;
+    constructor Create(aType,aName : TResourceDesc); override;
+    destructor Destroy; override;
+    procedure UpdateRawData; override;
+    procedure SetCustomBitmapDataStream(aStream : TStream);
+    property BitmapData : TStream read GetBitmapData;
+  end;
+
+
+implementation
+
+uses
+  resfactory, resdatastream;
+
+type
+  TBitmapFileHeader = packed record
+    Magic : word;
+    FileSize : longword;
+    Reserved : longword;
+    DataOffset : longword;
+  end;
+  
+const
+  hdrsize = sizeof(TBitmapFileHeader);
+
+type
+
+  { TBitmapCachedDataStream }
+
+  TBitmapCachedDataStream = class(TCachedDataStream)
+  private
+    fHeader : TMemoryStream;
+    procedure InitHeader(aStream : TStream);
+    function CalcDataOffset(aStream : TStream) : longword;
+  protected
+    function ReadFromSubStream(aStream : TStream; var Buffer; aPosition : int64; aCount : longint) : longint;
+  public
+    constructor Create(aStream : TStream;  aResource : TAbstractResource; aSize : int64); override;
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+  end;
+
+procedure TBitmapCachedDataStream.InitHeader(aStream: TStream);
+var bmphdr : TBitmapFileHeader;
+begin
+  bmphdr.Magic:=$4d42;
+  bmphdr.FileSize:=aStream.Size+hdrsize;
+  bmphdr.Reserved:=0;
+  bmphdr.DataOffset:=CalcDataOffset(aStream);
+  {$IFDEF ENDIAN_BIG}
+  bmphdr.Magic:=SwapEndian(bmphdr.Magic);
+  bmphdr.FileSize:=SwapEndian(bmphdr.FileSize);
+  bmphdr.Reserved:=SwapEndian(bmphdr.Reserved);
+  bmphdr.DataOffset:=SwapEndian(bmphdr.DataOffset);
+  {$ENDIF}
+  fHeader.Position:=0;
+  fHeader.WriteBuffer(bmphdr,hdrsize);
+end;
+
+function TBitmapCachedDataStream.CalcDataOffset(aStream: TStream): longword;
+const
+  BI_BITFIELDS = 3;
+var oldpos : int64;
+    compression, clrused : longword;
+    bitcount,palentries : word;
+    infohdrsize : longword;
+begin
+//  Data offset: bmp file header + bmp info header + [mask] + [palette]
+  Result:=0;
+  if aStream.Size<$28 then exit;
+  oldpos:=aStream.Position;
+  aStream.Position:=0;
+  aStream.ReadBuffer(infohdrsize,4);
+  aStream.Position:=14;
+  aStream.ReadBuffer(bitcount,2);
+  aStream.ReadBuffer(compression,4);
+  aStream.Seek(12,soFromCurrent);
+  aStream.ReadBuffer(clrused,4);
+  {$IFDEF ENDIAN_BIG}
+  infohdrsize:=SwapEndian(infohdrsize);
+  bitcount:=SwapEndian(bitcount);
+  compression:=SwapEndian(compression);
+  clrused:=SwapEndian(clrused);
+  {$ENDIF}
+  aStream.Position:=oldpos;
+  palentries:=0;
+  if ((compression=BI_BITFIELDS) and (bitcount in [16,32])) then
+    inc(Result,12)  //arbitrary mask
+  else if clrused>0 then palentries:=clrused
+  else if bitcount<=8 then palentries:=1 shl bitcount;
+  inc(Result,palentries*4);
+  inc(Result,hdrsize+infohdrsize);
+end;
+
+function TBitmapCachedDataStream.ReadFromSubStream(aStream: TStream;
+  var Buffer; aPosition: int64; aCount: longint): longint;
+var oldpos : int64;
+begin
+  Result:=aStream.Size-aPosition;
+  if aCount<Result then Result:=aCount;
+  if Result<0 then Result:=0;
+  oldpos:=aStream.Position;
+  aStream.Position:=aPosition;
+  Result:=aStream.Read(Buffer,Result);
+  aStream.Position:=oldpos;
+end;
+
+constructor TBitmapCachedDataStream.Create(aStream: TStream;  aResource : TAbstractResource; aSize: int64);
+begin
+  inherited Create(aStream,aResource,aSize);
+  fHeader:=TMemoryStream.Create;
+  inc(fSize,hdrsize);
+  InitHeader(aStream);
+end;
+
+destructor TBitmapCachedDataStream.Destroy;
+begin
+  fHeader.Free;
+end;
+
+function TBitmapCachedDataStream.Read(var Buffer; Count: Longint): Longint;
+var toread,read_in : longint;
+    b : pbyte;
+begin
+  Result:=0;
+  toread:=fSize-Position;
+  if Count<toread then toread:=Count;
+  if toread<0 then toread:=0;
+  b:=@buffer;
+
+  read_in:=ReadFromSubStream(fHeader,b^,fPosition,toread);
+  inc(fPosition,read_in);
+  inc(b,read_in);
+  inc(Result,read_in);
+  dec(toread,read_in);
+
+  read_in:=ReadFromSubStream(fStream,b^,fPosition-hdrsize,toread);
+  inc(fPosition,read_in);
+  inc(Result,read_in);
+end;
+
+
+{ TBitmapResource }
+
+function TBitmapResource.GetBitmapData: TStream;
+begin
+  if fBitmapData = nil then
+    fBitmapData:=TResourceDataStream.Create(RawData,self,DataSize,TBitmapCachedDataStream);
+  Result:=fBitmapData;
+end;
+
+procedure TBitmapResource.UpdateRawData;
+begin
+  if TResourceDataStream(BitmapData).Cached then exit; //no need to update rawdata
+  //rawdata = bitmapdata without bitmap file header
+  BitmapData.Position:=hdrsize;
+  RawData.Size:=0;
+  RawData.Position:=0;
+  RawData.CopyFrom(BitmapData,BitmapData.Size-hdrsize);
+  FreeAndNil(fBitmapData);
+end;
+
+function TBitmapResource.GetType: TResourceDesc;
+begin
+  Result:=fType;
+end;
+
+function TBitmapResource.GetName: TResourceDesc;
+begin
+  Result:=fName;
+end;
+
+function TBitmapResource.ChangeDescTypeAllowed(aDesc: TResourceDesc): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+function TBitmapResource.ChangeDescValueAllowed(aDesc: TResourceDesc): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+procedure TBitmapResource.NotifyResourcesLoaded;
+begin
+end;
+
+constructor TBitmapResource.Create;
+begin
+  inherited Create;
+  fType:=TResourceDesc.Create(RT_BITMAP);
+  fName:=TResourceDesc.Create(1);
+  SetDescOwner(fType);
+  SetDescOwner(fName);
+  fBitmapData:=nil;
+end;
+
+constructor TBitmapResource.Create(aType, aName: TResourceDesc);
+begin
+  Create;
+  fName.Assign(aName);
+end;
+
+destructor TBitmapResource.Destroy;
+begin
+  if fBitmapData<>nil then fBitmapData.Free;
+  fType.Free;
+  fName.Free;
+  inherited Destroy;
+end;
+
+procedure TBitmapResource.SetCustomBitmapDataStream(aStream: TStream);
+begin
+  TResourceDataStream(BitmapData).SetCustomStream(aStream);
+end;
+
+initialization
+  TResourceFactory.RegisterResourceClass(RT_BITMAP,TBitmapResource);
+
+end.
+

+ 164 - 0
packages/fcl-res/src/coffconsts.pp

@@ -0,0 +1,164 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Constants used by COFF resource reader and writer
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit coffconsts;
+
+{$MODE OBJFPC}
+
+interface
+
+//Machine types
+const
+  IMAGE_FILE_MACHINE_UNKNOWN         = 0;
+  IMAGE_FILE_MACHINE_I386            = $014c;  // Intel 386.
+{
+  IMAGE_FILE_MACHINE_R3000           = $0162;  // MIPS little-endian, 0x160 big-endian
+  IMAGE_FILE_MACHINE_R4000           = $0166;  // MIPS little-endian
+  IMAGE_FILE_MACHINE_R10000          = $0168;  // MIPS little-endian
+  IMAGE_FILE_MACHINE_WCEMIPSV2       = $0169;  // MIPS little-endian WCE v2
+  IMAGE_FILE_MACHINE_ALPHA           = $0184;  // Alpha_AXP
+  IMAGE_FILE_MACHINE_SH3             = $01a2;  // SH3 little-endian
+  IMAGE_FILE_MACHINE_SH3DSP          = $01a3;
+  IMAGE_FILE_MACHINE_SH3E            = $01a4;  // SH3E little-endian
+  IMAGE_FILE_MACHINE_SH4             = $01a6;  // SH4 little-endian
+  IMAGE_FILE_MACHINE_SH5             = $01a8;  // SH5
+}
+  IMAGE_FILE_MACHINE_ARM             = $01c0;  // ARM Little-Endian
+{
+  IMAGE_FILE_MACHINE_THUMB           = $01c2;
+  IMAGE_FILE_MACHINE_AM33            = $01d3;
+  IMAGE_FILE_MACHINE_POWERPC         = $01F0;  // IBM PowerPC Little-Endian
+  IMAGE_FILE_MACHINE_POWERPCFP       = $01f1;
+  IMAGE_FILE_MACHINE_IA64            = $0200;  // Intel 64
+  IMAGE_FILE_MACHINE_MIPS16          = $0266;  // MIPS
+  IMAGE_FILE_MACHINE_ALPHA64         = $0284;  // ALPHA64
+  IMAGE_FILE_MACHINE_MIPSFPU         = $0366;  // MIPS
+  IMAGE_FILE_MACHINE_MIPSFPU16       = $0466;  // MIPS
+  IMAGE_FILE_MACHINE_AXP64           = IMAGE_FILE_MACHINE_ALPHA64;
+  IMAGE_FILE_MACHINE_TRICORE         = $0520;  // Infineon
+  IMAGE_FILE_MACHINE_CEF             = $0CEF;
+  IMAGE_FILE_MACHINE_EBC             = $0EBC;  // EFI Byte Code
+}
+  IMAGE_FILE_MACHINE_AMD64           = $8664;  // AMD64 (K8)
+{
+  IMAGE_FILE_MACHINE_M32R            = $9041;  // M32R little-endian
+  IMAGE_FILE_MACHINE_CEE             = $C0EE;
+}
+
+//Coff header characteristics
+const
+  IMAGE_FILE_RELOCS_STRIPPED         = $0001;  // Relocation info stripped from file.
+  IMAGE_FILE_EXECUTABLE_IMAGE        = $0002;  // File is executable  (i.e. no unresolved externel references).
+  IMAGE_FILE_LINE_NUMS_STRIPPED      = $0004;  // Line nunbers stripped from file.
+  IMAGE_FILE_LOCAL_SYMS_STRIPPED     = $0008;  // Local symbols stripped from file.
+  IMAGE_FILE_AGGRESIVE_WS_TRIM       = $0010;  // Agressively trim working set
+  IMAGE_FILE_LARGE_ADDRESS_AWARE     = $0020;  // App can handle >2gb addresses
+  IMAGE_FILE_BYTES_REVERSED_LO       = $0080;  // Bytes of machine word are reversed.
+  IMAGE_FILE_32BIT_MACHINE           = $0100;  // 32 bit word machine.
+  IMAGE_FILE_DEBUG_STRIPPED          = $0200;  // Debugging info stripped from file in .DBG file
+  IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = $0400;  // If Image is on removable media, copy and run from the swap file.
+  IMAGE_FILE_NET_RUN_FROM_SWAP       = $0800;  // If Image is on Net, copy and run from the swap file.
+  IMAGE_FILE_SYSTEM                  = $1000;  // System File.
+  IMAGE_FILE_DLL                     = $2000;  // File is a DLL.
+  IMAGE_FILE_UP_SYSTEM_ONLY          = $4000;  // File should only be run on a UP machine
+  IMAGE_FILE_BYTES_REVERSED_HI       = $8000;  // Bytes of machine word are reversed.
+
+//Section header characteristics
+const
+  IMAGE_SCN_CNT_CODE                 = $00000020;  // Section contains code.
+  IMAGE_SCN_CNT_INITIALIZED_DATA     = $00000040;  // Section contains initialized data.
+  IMAGE_SCN_CNT_UNINITIALIZED_DATA   = $00000080;  // Section contains uninitialized data.
+  IMAGE_SCN_LNK_OTHER                = $00000100;  // Reserved.
+  IMAGE_SCN_LNK_INFO                 = $00000200;  // Section contains comments or some other type of information.
+  IMAGE_SCN_LNK_REMOVE               = $00000800;  // Section contents will not become part of image.
+  IMAGE_SCN_LNK_COMDAT               = $00001000;  // Section contents comdat.
+  IMAGE_SCN_GPREL                    = $00008000;  // Section content can be accessed relative to GP
+  IMAGE_SCN_ALIGN_1BYTES             = $00100000;  //
+  IMAGE_SCN_ALIGN_2BYTES             = $00200000;  //
+  IMAGE_SCN_ALIGN_4BYTES             = $00300000;  //
+  IMAGE_SCN_ALIGN_8BYTES             = $00400000;  //
+  IMAGE_SCN_ALIGN_16BYTES            = $00500000;  // Default alignment if no others are specified.
+  IMAGE_SCN_ALIGN_32BYTES            = $00600000;  //
+  IMAGE_SCN_ALIGN_64BYTES            = $00700000;  //
+  IMAGE_SCN_ALIGN_128BYTES           = $00800000;  //
+  IMAGE_SCN_ALIGN_256BYTES           = $00900000;  //
+  IMAGE_SCN_ALIGN_512BYTES           = $00A00000;  //
+  IMAGE_SCN_ALIGN_1024BYTES          = $00B00000;  //
+  IMAGE_SCN_ALIGN_2048BYTES          = $00C00000;  //
+  IMAGE_SCN_ALIGN_4096BYTES          = $00D00000;  //
+  IMAGE_SCN_ALIGN_8192BYTES          = $00E00000;  //
+  IMAGE_SCN_LNK_NRELOC_OVFL          = $01000000;  // Section contains extended relocations.
+  IMAGE_SCN_MEM_DISCARDABLE          = $02000000;  // Section can be discarded.
+  IMAGE_SCN_MEM_NOT_CACHED           = $04000000;  // Section is not cachable.
+  IMAGE_SCN_MEM_NOT_PAGED            = $08000000;  // Section is not pageable.
+  IMAGE_SCN_MEM_SHARED               = $10000000;  // Section is shareable.
+  IMAGE_SCN_MEM_EXECUTE              = $20000000;  // Section is executable.
+  IMAGE_SCN_MEM_READ                 = $40000000;  // Section is readable.
+  IMAGE_SCN_MEM_WRITE                = $80000000;  // Section is writeable.
+
+const
+// I386 relocation types.
+  IMAGE_REL_I386_ABSOLUTE       = $0000;  // Reference is absolute, no relocation is necessary
+  IMAGE_REL_I386_DIR16          = $0001;  // Direct 16-bit reference to the symbols virtual address
+  IMAGE_REL_I386_REL16          = $0002;  // PC-relative 16-bit reference to the symbols virtual address
+  IMAGE_REL_I386_DIR32          = $0006;  // Direct 32-bit reference to the symbols virtual address
+  IMAGE_REL_I386_DIR32NB        = $0007;  // Direct 32-bit reference to the symbols virtual address, base not included
+  IMAGE_REL_I386_SEG12          = $0009;  // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
+  IMAGE_REL_I386_SECTION        = $000A;
+  IMAGE_REL_I386_SECREL         = $000B;
+  IMAGE_REL_I386_TOKEN          = $000C;  // clr token
+  IMAGE_REL_I386_SECREL7        = $000D;  // 7 bit offset from base of section containing target
+  IMAGE_REL_I386_REL32          = $0014;  // PC-relative 32-bit reference to the symbols virtual address
+
+// ARM relocation types.
+  IMAGE_REL_ARM_ABSOLUTE        = $0000;  // No relocation required
+  IMAGE_REL_ARM_ADDR32          = $0001;  // 32 bit address
+  IMAGE_REL_ARM_ADDR32NB        = $0002;  // 32 bit address w/o image base
+  IMAGE_REL_ARM_BRANCH24        = $0003;  // 24 bit offset << 2 & sign ext.
+  IMAGE_REL_ARM_BRANCH11        = $0004;  // Thumb: 2 11 bit offsets
+  IMAGE_REL_ARM_TOKEN           = $0005;  // clr token
+  IMAGE_REL_ARM_GPREL12         = $0006;  // GP-relative addressing (ARM)
+  IMAGE_REL_ARM_GPREL7          = $0007;  // GP-relative addressing (Thumb)
+  IMAGE_REL_ARM_BLX24           = $0008;
+  IMAGE_REL_ARM_BLX11           = $0009;
+  IMAGE_REL_ARM_SECTION         = $000E;  // Section table index
+  IMAGE_REL_ARM_SECREL          = $000F;  // Offset within section
+
+// x64 relocation types.
+  IMAGE_REL_AMD64_ABSOLUTE      = $0000;  // Reference is absolute, no relocation is necessary
+  IMAGE_REL_AMD64_ADDR64        = $0001;  // 64-bit address (VA).
+  IMAGE_REL_AMD64_ADDR32        = $0002;  // 32-bit address (VA).
+  IMAGE_REL_AMD64_ADDR32NB      = $0003;  // 32-bit address w/o image base (RVA).
+  IMAGE_REL_AMD64_REL32         = $0004;  // 32-bit relative address from byte following reloc
+  IMAGE_REL_AMD64_REL32_1       = $0005;  // 32-bit relative address from byte distance 1 from reloc
+  IMAGE_REL_AMD64_REL32_2       = $0006;  // 32-bit relative address from byte distance 2 from reloc
+  IMAGE_REL_AMD64_REL32_3       = $0007;  // 32-bit relative address from byte distance 3 from reloc
+  IMAGE_REL_AMD64_REL32_4       = $0008;  // 32-bit relative address from byte distance 4 from reloc
+  IMAGE_REL_AMD64_REL32_5       = $0009;  // 32-bit relative address from byte distance 5 from reloc
+  IMAGE_REL_AMD64_SECTION       = $000A;  // Section index
+  IMAGE_REL_AMD64_SECREL        = $000B;  // 32 bit offset from base of section containing target
+  IMAGE_REL_AMD64_SECREL7       = $000C;  // 7 bit unsigned offset from base of section containing target
+  IMAGE_REL_AMD64_TOKEN         = $000D;  // 32 bit metadata token
+  IMAGE_REL_AMD64_SREL32        = $000E;  // 32 bit signed span-dependent value emitted into object
+  IMAGE_REL_AMD64_PAIR          = $000F;
+  IMAGE_REL_AMD64_SSPAN32       = $0010;  // 32 bit signed span-dependent value applied at link time
+
+const
+// storage classes
+  IMAGE_SYM_CLASS_STATIC        = $0003;
+
+implementation
+
+end.

+ 308 - 0
packages/fcl-res/src/coffreader.pp

@@ -0,0 +1,308 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for COFF files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit coffreader;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, resourcetree, cofftypes;
+
+type
+
+  { TCoffResourceReader }
+
+  TCoffResourceReader = class (TAbstractResourceReader)
+  private
+    fDescription: string;
+    fExtensions: string;
+    fCoffHeader : TCoffHeader;
+    fResSectHeader : TCoffSectionHeader;
+    fResSectStart : int64;
+    fRoot : TRootResTreeNode;
+    fMachineType : TCoffMachineType;
+    function CheckRsrcName(aName : TSectionName) : boolean;
+    function ReadCoffHeader(aStream : TStream) : boolean;
+    function FindResSectionHeader(aStream : TStream) : boolean;
+    procedure ReadResourceTree(aStream : TStream; aResources: TResources);
+    procedure ReadNodeTable(aStream : TStream; aNode : TResourceTreeNode; aResources: TResources);
+    procedure ReadNodeDirEntry(aStream : TStream; aParent : TResourceTreeNode; aResources: TResources);
+    function ReadResString(aStream : TStream; aRVA : longword) : string;
+    procedure ReadResDataEntry(aStream : TStream; aNode : TResourceTreeNode; aResources: TResources);
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Load(aResources : TResources; aStream : TStream); override;
+    function CheckMagic(aStream : TStream) : boolean; override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    property MachineType : TCoffMachineType read fMachineType;
+  end;
+
+
+implementation
+
+uses coffconsts, resdatastream;
+
+{ TCoffResourceReader }
+
+function TCoffResourceReader.CheckRsrcName(aName: TSectionName): boolean;
+var s : string;
+begin
+  Result:=aName=RSRCSectName;
+  if not result then
+  begin
+    s:=aName;
+    Result:=copy(s,1,6)='.rsrc$';
+  end;
+end;
+
+function TCoffResourceReader.ReadCoffHeader(aStream: TStream): boolean;
+var hdr : TCoffHeader;
+begin
+  Result:=false;
+
+  try
+    aStream.ReadBuffer(hdr,sizeof(hdr));
+  except
+    on e : EReadError do exit;
+  end;
+  
+  {$IFDEF ENDIAN_BIG}
+  hdr.machine:=SwapEndian(hdr.machine);
+  hdr.numsects:=SwapEndian(hdr.numsects);
+  hdr.timestamp:=SwapEndian(hdr.timestamp);
+  hdr.symtableptr:=SwapEndian(hdr.symtableptr);
+  hdr.symnum:=SwapEndian(hdr.symnum);
+  hdr.opthdrsize:=SwapEndian(hdr.opthdrsize);
+  hdr.characteristics:=SwapEndian(hdr.characteristics);
+  {$ENDIF}
+
+  case hdr.machine of
+    IMAGE_FILE_MACHINE_I386  : fMachineType:=cmti386;
+    IMAGE_FILE_MACHINE_ARM   : fMachineType:=cmtarm;
+    IMAGE_FILE_MACHINE_AMD64 : fMachineType:=cmtx8664
+    else exit;
+  end;
+
+  if hdr.opthdrsize>0 then
+    aStream.Seek(hdr.opthdrsize,soFromCurrent);
+  Result:=true;
+  fCoffHeader:=hdr;
+end;
+
+function TCoffResourceReader.FindResSectionHeader(aStream: TStream) : boolean;
+var hdr : TCoffSectionHeader;
+    i : integer;
+begin
+  Result:=true;
+  for i:=1 to fCoffHeader.NumSects do
+  begin
+    aStream.ReadBuffer(hdr,sizeof(hdr));
+
+    {$IFDEF ENDIAN_BIG}
+    hdr.VirtualSize:=SwapEndian(hdr.VirtualSize);
+    hdr.VirtualAddress:=SwapEndian(hdr.VirtualAddress);
+    hdr.SizeOfRawData:=SwapEndian(hdr.SizeOfRawData);
+    hdr.PointerToRawData:=SwapEndian(hdr.PointerToRawData);
+    hdr.PointerToRelocations:=SwapEndian(hdr.PointerToRelocations);
+    hdr.PointerToLineNumbers:=SwapEndian(hdr.PointerToLineNumbers);
+    hdr.NumberOfRelocations:=SwapEndian(hdr.NumberOfRelocations);
+    hdr.NumberOfLineNumbers:=SwapEndian(hdr.NumberOfLineNumbers);
+    hdr.Characteristics:=SwapEndian(hdr.Characteristics);
+    {$ENDIF}
+
+    if CheckRsrcName(hdr.Name) then
+    begin
+      fResSectHeader:=hdr;
+      fResSectStart:=hdr.PointerToRawData;
+      aStream.Position:=fResSectStart;
+      exit;
+    end;
+  end;
+  Result:=false;
+end;
+
+procedure TCoffResourceReader.ReadResourceTree(aStream: TStream; aResources: TResources);
+begin
+  fRoot:=TRootResTreeNode(GetTree(aResources));
+  ReadNodeTable(aStream,fRoot,aResources);
+end;
+
+procedure TCoffResourceReader.ReadNodeTable(aStream: TStream;
+  aNode: TResourceTreeNode; aResources: TResources);
+var table : TResDirTable;
+    i : integer;
+begin
+  aStream.ReadBuffer(table,sizeof(table));
+  {$IFDEF ENDIAN_BIG}
+  table.Characteristics:=SwapEndian(table.Characteristics);
+  table.TimeStamp:=SwapEndian(table.TimeStamp);
+  table.VerMajor:=SwapEndian(table.VerMajor);
+  table.VerMinor:=SwapEndian(table.VerMinor);
+  table.NamedEntriesCount:=SwapEndian(table.NamedEntriesCount);
+  table.IDEntriesCount:=SwapEndian(table.IDEntriesCount);
+  {$ENDIF}
+
+  for i:=1 to table.NamedEntriesCount do
+    ReadNodeDirEntry(aStream,aNode,aResources);
+  for i:=1 to table.IDEntriesCount do
+    ReadNodeDirEntry(aStream,aNode,aResources);
+end;
+
+procedure TCoffResourceReader.ReadNodeDirEntry(aStream: TStream;
+  aParent : TResourceTreeNode; aResources: TResources);
+var entry : TResDirEntry;
+    desc : TResourceDesc;
+    node : TResourceTreeNode;
+    oldpos : int64;
+begin
+  aStream.ReadBuffer(entry,sizeof(entry));
+  oldpos:=aStream.Position;
+  {$IFDEF ENDIAN_BIG}
+  entry.NameID:=SwapEndian(entry.NameID);
+  entry.DataSubDirRVA:=SwapEndian(entry.DataSubDirRVA);
+  {$ENDIF}
+
+  desc:=TResourceDesc.Create;
+  try
+    if (entry.NameID and $80000000) = $80000000 then
+      desc.Name:=ReadResString(aStream,(entry.NameID and $7FFFFFFF))
+    else desc.ID:=entry.NameID;
+    node:=aParent.CreateSubNode(desc);
+
+    if (entry.DataSubDirRVA and $80000000) = $80000000 then
+    begin
+      aStream.Position:=fResSectStart+(entry.DataSubDirRVA and $7FFFFFFF);
+      ReadNodeTable(aStream,node,aResources);
+    end
+    else
+    begin
+      aStream.Position:=fResSectStart+entry.DataSubDirRVA;
+      ReadResDataEntry(aStream,node,aResources);
+    end;
+    aStream.Position:=oldpos;
+  finally
+    desc.Free;
+  end;
+end;
+
+function TCoffResourceReader.ReadResString(aStream: TStream; aRVA: longword
+  ): string;
+var oldpos : int64;
+    ws : widestring;
+    w : word;
+    i : integer;
+begin
+  oldpos:=aStream.Position;
+  aStream.Position:=fResSectStart+aRVA;
+
+  aStream.ReadBuffer(w,2);
+  {$IFDEF ENDIAN_BIG}
+  w:=SwapEndian(w);
+  {$ENDIF}
+  setlength(ws,w);
+
+  for i:=1 to length(ws) do
+  begin
+    aStream.ReadBuffer(w,2);
+    {$IFDEF ENDIAN_BIG}
+    w:=SwapEndian(w);
+    {$ENDIF}
+    ws[i]:=widechar(w);
+  end;
+  aStream.Position:=oldpos;
+  Result:=ws;
+end;
+
+procedure TCoffResourceReader.ReadResDataEntry(aStream: TStream;
+  aNode: TResourceTreeNode; aResources: TResources);
+var entry : TResDataEntry;
+    res : TAbstractResource;
+    RawData : TResourceDataStream;
+begin
+  aStream.ReadBuffer(entry,sizeof(entry));
+  {$IFDEF ENDIAN_BIG}
+  entry.DataRVA:=SwapEndian(entry.DataRVA);
+  entry.Size:=SwapEndian(entry.Size);
+  entry.Codepage:=SwapEndian(entry.Codepage);
+  entry.Reserved:=SwapEndian(entry.Reserved);
+  {$ENDIF}
+
+  res:=aNode.CreateResource;
+  if res=nil then
+    raise EResourceDuplicateException.CreateFmt(SResDuplicate,[
+      aNode.Data._Type.Name,aNode.Data.Name.Name,aNode.Data.LangID]);
+  res.CodePage:=entry.Codepage;
+  SetDataSize(res,entry.Size);
+  aStream.Position:=fResSectStart+entry.DataRVA-fResSectHeader.VirtualAddress;
+  SetDataOffset(res,aStream.Position);
+  RawData:=TResourceDataStream.Create(aStream,res,res.DataSize,TCachedResourceDataStream);
+  SetRawData(res,RawData);
+  AddNoTree(aResources,res);
+end;
+
+function TCoffResourceReader.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TCoffResourceReader.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TCoffResourceReader.Load(aResources: TResources; aStream: TStream);
+begin
+  if not ReadCoffHeader(aStream) then
+    raise EResourceReaderWrongFormatException.Create('');
+  try
+    if not FindResSectionHeader(aStream) then exit; //no resources in this file.
+    ReadResourceTree(aStream,aResources);
+  except
+    on e : EReadError do
+      raise EResourceReaderUnexpectedEndOfStreamException.Create('');
+  end;
+end;
+
+function TCoffResourceReader.CheckMagic(aStream: TStream): boolean;
+begin
+  Result:=ReadCoffHeader(aStream);
+end;
+
+constructor TCoffResourceReader.Create;
+begin
+  fExtensions:='.o .obj';
+  fDescription:='COFF resource reader';
+  fResSectStart:=0;
+  FillByte(fCoffHeader,sizeof(fCoffHeader),0);
+  FillByte(fResSectHeader,sizeof(fResSectHeader),0);
+  fRoot:=nil;
+  fMachineType:=cmti386;
+end;
+
+destructor TCoffResourceReader.Destroy;
+begin
+
+end;
+
+initialization
+  TResources.RegisterReader('.o',TCoffResourceReader);
+  TResources.RegisterReader('.obj',TCoffResourceReader);
+
+end.

+ 87 - 0
packages/fcl-res/src/cofftypes.pp

@@ -0,0 +1,87 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Types used by COFF resource reader and writer
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit cofftypes;
+
+{$MODE OBJFPC}
+
+interface
+
+type
+  TCoffMachineType = (cmti386, cmtarm, cmtx8664);
+
+type
+  TSectionName = array [0..7] of char;
+
+const
+  RSRCSectName : TSectionName = '.rsrc'+#0+#0+#0;
+
+type
+  TCoffHeader = packed record
+    Machine : word;
+    NumSects : word;
+    TimeStamp : longword;
+    SymTablePtr : longword;
+    SymNum : longword;
+    OptHdrSize : word;
+    Characteristics : word;
+  end;
+
+  TCoffSectionHeader = packed record
+    Name : TSectionName;
+    VirtualSize : longword;
+    VirtualAddress : longword;
+    SizeOfRawData : longword;
+    PointerToRawData : longword;
+    PointerToRelocations : longword;
+    PointerToLineNumbers : longword;
+    NumberOfRelocations : word;
+    NumberOfLineNumbers : word;
+    Characteristics : longword;
+  end;
+
+  TCoffSectionTable = packed record
+    Name : TSectionName;
+    Value : longword;
+    SectionNumber : word;
+    _type : word;
+    StorageClass : byte;
+    NumAuxSymbol : byte;
+  end;
+
+  TResDirTable = packed record
+    Characteristics : longword;
+    TimeStamp : longword;
+    VerMajor : word;
+    VerMinor : word;
+    NamedEntriesCount : word;
+    IDEntriesCount : word;
+  end;
+
+  TResDirEntry = packed record
+    NameID : longword;
+    DataSubDirRVA : longword;
+  end;
+
+  TResDataEntry = packed record
+    DataRVA : longword;
+    Size : longword;
+    Codepage : longword;
+    Reserved : longword;
+  end;
+
+implementation
+
+end.

+ 637 - 0
packages/fcl-res/src/coffwriter.pp

@@ -0,0 +1,637 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource writer for COFF files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit coffwriter;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, resourcetree, cofftypes;
+
+type
+
+  { TResourceStringTable }
+
+  TResourceStringTable = class
+  private
+    fList : TStringList;
+    fStartRVA : longword;
+    fCurrRVA : longword;
+    fEndRVA : longword;
+    function GetString(index : integer) : string;
+    function GetCount : integer;
+    procedure SetStartRVA(aValue : longword);
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Add(s : string);
+    procedure Clear;
+    property Count : integer read GetCount;
+    property Items[index : integer] : string read GetString; default;
+    property StartRVA : longword read fStartRVA write SetStartRVA;
+    property CurrRVA : longword read fCurrRVA;
+    property EndRVA : longword read fEndRVA;
+  end;
+
+  TCoffRelocation = packed record
+    VirtualAddress : longword;
+    SymTableIndex : longword;
+    _type : word;
+  end;
+  PCoffRelocation = ^TCoffRelocation;
+  
+  { TCoffRelocations }
+
+  TCoffRelocations = class
+  private
+    fList : TFPList;
+    fStartAddress : longword;
+  protected
+    function GetCount : integer;
+    function GetRelocation(index : integer) : PCoffRelocation;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Add(aAddress : longword; aType : word);
+    procedure Clear;
+    property Count : integer read GetCount;
+    property Items[index : integer] : PCoffRelocation read GetRelocation; default;
+    property StartAddress : longword read fStartAddress write fStartAddress;
+  end;
+
+  { TCoffResourceWriter }
+
+  TCoffResourceWriter = class (TAbstractResourceWriter)
+  private
+    fExtensions : string;
+    fDescription : string;
+    fRoot : TRootResTreeNode;
+    fResStringTable : TResourceStringTable;
+    fResDataEntryCurrentRVA : longword;
+    fRelocations : TCoffRelocations;
+    fSymTablePtr : longword;
+    fMachineType : TCoffMachineType;
+    procedure AlignDword(aStream : TStream);
+    function NextAlignedDword(aValue : longword) : longword;
+    procedure SetNodeStringRVA(aNode : TResourceTreeNode);
+    function PrescanNode(aNode : TResourceTreeNode) : longword;
+    procedure PrescanResourceTree;
+    procedure WriteEmptyCoffHeader(aStream : TStream);
+    procedure WriteEmptySectionHeader(aStream : TStream);
+    procedure WriteResDirTables(aStream : TStream);
+    procedure WriteNodeTables(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteNodeDirEntry(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteResStringTable(aStream : TStream);
+    procedure WriteResString(aStream : TStream; TheString : string);
+    procedure WriteResDataEntries(aStream : TStream);
+    procedure WriteResDataEntry(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteRawData(aStream : TStream);
+    procedure WriteNodeRawData(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteRelocations(aStream : TStream);
+    procedure WriteRelocation(aStream : TStream; aRelocation : PCoffRelocation);
+    procedure WriteSymbolTable(aStream : TStream);
+    procedure WriteEmptyCoffStringTable(aStream : TStream);
+    procedure FixCoffHeader(aStream : TStream);
+    procedure FixSectionHeader(aStream : TStream);
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Write(aResources : TResources; aStream : TStream); override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    property MachineType : TCoffMachineType read fMachineType write fMachineType;
+  end;
+
+implementation
+
+uses coffconsts;
+
+(* Utility function to calculate the timestamp *)
+(*
+function DateTimeToTimeT(aDate : TDateTime) : longint;
+var days : integer;
+    seconds : integer;
+begin
+  days:=trunc(aDate);
+  seconds:=trunc(SecsPerDay*frac(aDate));
+  dec(days,UnixDateDelta);
+  Result:=SecsPerDay*days+seconds;
+end;
+*)
+
+{ TCoffResourceWriter }
+
+procedure TCoffResourceWriter.AlignDword(aStream: TStream);
+var topad : integer;
+    lw : longword;
+begin
+  lw:=0;
+  topad:=4-(aStream.Position mod 4);
+  if topad<>4 then aStream.WriteBuffer(lw,topad);
+end;
+
+procedure TCoffResourceWriter.WriteEmptyCoffHeader(aStream: TStream);
+var hdr : TCoffHeader;
+begin
+  FillByte(hdr,sizeof(hdr),0);
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+end;
+
+procedure TCoffResourceWriter.WriteEmptySectionHeader(aStream: TStream);
+var hdr : TCoffSectionHeader;
+begin
+  FillByte(hdr,sizeof(hdr),0);
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+end;
+
+procedure TCoffResourceWriter.WriteResDirTables(aStream: TStream);
+begin
+  fResDataEntryCurrentRVA:=fResStringTable.EndRVA;
+  fRelocations.Clear;
+  WriteNodeTables(aStream,fRoot);
+end;
+
+procedure TCoffResourceWriter.WriteNodeTables(aStream : TStream; aNode: TResourceTreeNode);
+var table : TResDirTable;
+    i : integer;
+begin
+  if aNode.IsLeaf then exit;
+  table.Characteristics:=0;
+  table.TimeStamp:=0; //DateTimeToTimeT(now);   //we need a crossplatform way to have it UTC
+  table.VerMajor:=0;
+  table.VerMinor:=0;
+  table.NamedEntriesCount:=aNode.NamedCount;
+  table.IDEntriesCount:=aNode.IDCount;
+  {$IFDEF ENDIAN_BIG}
+  table.Characteristics:=SwapEndian(table.Characteristics);
+  table.TimeStamp:=SwapEndian(table.TimeStamp);
+  table.VerMajor:=SwapEndian(table.VerMajor);
+  table.VerMinor:=SwapEndian(table.VerMinor);
+  table.NamedEntriesCount:=SwapEndian(table.NamedEntriesCount);
+  table.IDEntriesCount:=SwapEndian(table.IDEntriesCount);
+  {$ENDIF}
+  aStream.WriteBuffer(table,sizeof(Table));
+
+  for i:=0 to aNode.NamedCount-1 do
+    WriteNodeDirEntry(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteNodeDirEntry(aStream,aNode.IDEntries[i]);
+
+  for i:=0 to aNode.NamedCount-1 do
+    WriteNodeTables(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteNodeTables(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TCoffResourceWriter.WriteNodeDirEntry(aStream: TStream;
+  aNode: TResourceTreeNode);
+var entry : TResDirEntry;
+    reloctype : longword;
+begin
+  case aNode.Desc.DescType of
+    dtID : entry.NameID:=aNode.Desc.ID;
+    dtName : entry.NameID:=(aNode.NameRva+fResStringTable.StartRVA) or $80000000;
+  end;
+  if aNode.IsLeaf then
+  begin
+    entry.DataSubDirRVA:=fResDataEntryCurrentRVA;
+    inc(fResDataEntryCurrentRVA,sizeof(TResDataEntry));
+    case fMachineType of
+      cmti386  : reloctype:=IMAGE_REL_I386_DIR32NB;
+      cmtarm   : reloctype:=IMAGE_REL_ARM_ADDR32NB;
+      cmtx8664 : reloctype:=IMAGE_REL_AMD64_ADDR32NB;
+    end;
+    fRelocations.Add(entry.DataSubDirRVA,reloctype);
+  end
+  else entry.DataSubDirRVA:=aNode.SubDirRVA or $80000000;
+
+  {$IFDEF ENDIAN_BIG}
+  entry.NameID:=SwapEndian(entry.NameID);
+  entry.DataSubDirRVA:=SwapEndian(entry.DataSubDirRVA);
+  {$ENDIF}
+  aStream.WriteBuffer(entry,sizeof(entry));
+end;
+
+procedure TCoffResourceWriter.WriteResStringTable(aStream: TStream);
+var i : integer;
+    lw : longword;
+begin
+  for i:=0 to fResStringTable.Count-1 do
+    WriteResString(aStream,fResStringTable[i]);
+
+  //align on dword boundaries
+  i:=fResStringTable.EndRVA-fResStringTable.CurrRVA;
+  if i>0 then
+  begin
+    lw:=0;
+    aStream.WriteBuffer(lw,i);
+  end;
+end;
+
+procedure TCoffResourceWriter.WriteResString(aStream: TStream; TheString: string
+  );
+var ws : widestring;
+    w : word;
+    i : integer;
+begin
+  w:=length(thestring);
+  {$IFDEF ENDIAN_BIG}
+  w:=SwapEndian(w);
+  {$ENDIF}
+  aStream.WriteBuffer(w,2);
+  ws:=TheString;
+  for i:=1 to length(ws) do
+  begin
+    w:=word(ws[i]);
+    {$IFDEF ENDIAN_BIG}
+    w:=SwapEndian(w);
+    {$ENDIF}
+    aStream.WriteBuffer(w,2);
+  end;
+end;
+
+procedure TCoffResourceWriter.WriteResDataEntries(aStream: TStream);
+begin
+  WriteResDataEntry(aStream,fRoot);
+end;
+
+procedure TCoffResourceWriter.WriteResDataEntry(aStream: TStream;
+  aNode: TResourceTreeNode);
+var entry : TResDataEntry;
+    i : integer;
+    res : TAbstractResource;
+begin
+  if aNode.IsLeaf then
+  begin
+    res:=aNode.Data;
+    aNode.DataRVA:=fResDataEntryCurrentRVA;
+    entry.DataRVA:=aNode.DataRVA;
+    entry.Size:=res.DataSize;
+    entry.Codepage:=res.CodePage;
+    entry.Reserved:=0;
+    inc(fResDataEntryCurrentRVA,entry.Size);
+    fResDataEntryCurrentRVA:=NextAlignedDword(fResDataEntryCurrentRVA);
+    {$IFDEF ENDIAN_BIG}
+    entry.DataRVA:=SwapEndian(entry.DataRVA);
+    entry.Size:=SwapEndian(entry.Size);
+    entry.Codepage:=SwapEndian(entry.Codepage);
+    entry.Reserved:=SwapEndian(entry.Reserved);
+    {$ENDIF}
+    aStream.WriteBuffer(entry,sizeof(entry));
+  end;
+  for i:=0 to aNode.NamedCount-1 do
+    WriteResDataEntry(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteResDataEntry(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TCoffResourceWriter.WriteRawData(aStream: TStream);
+begin
+  WriteNodeRawData(aStream,fRoot);
+end;
+
+procedure TCoffResourceWriter.WriteNodeRawData(aStream: TStream;
+  aNode: TResourceTreeNode);
+var i : integer;
+    res : TAbstractResource;
+begin
+  if aNode.IsLeaf then
+  begin
+    res:=aNode.Data;
+    res.RawData.Position:=0;
+    aStream.CopyFrom(res.RawData,res.DataSize);
+    AlignDword(aStream);
+  end;
+  for i:=0 to aNode.NamedCount-1 do
+    WriteNodeRawData(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteNodeRawData(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TCoffResourceWriter.WriteRelocations(aStream: TStream);
+var i : integer;
+begin
+  fRelocations.StartAddress:=aStream.Position;
+  for i:=0 to fRelocations.Count-1 do
+    WriteRelocation(aStream,fRelocations[i]);
+end;
+
+procedure TCoffResourceWriter.WriteRelocation(aStream: TStream;
+  aRelocation: PCoffRelocation);
+var r : TCoffRelocation;
+begin
+  r:=aRelocation^;
+  {$IFDEF ENDIAN_BIG}
+  r.VirtualAddress:=SwapEndian(r.VirtualAddress);
+  r.SymTableIndex:=SwapEndian(r.SymTableIndex);
+  r._type:=SwapEndian(r._type);;
+  {$ENDIF}
+  aStream.WriteBuffer(r,sizeof(r));
+end;
+
+procedure TCoffResourceWriter.WriteSymbolTable(aStream: TStream);
+var st : TCoffSectionTable;
+begin
+  fSymTablePtr:=aStream.Position;
+  st.Name:=RSRCSectName;
+  st.Value:=0;
+  st.SectionNumber:=1;
+  st._type:=0;
+  st.StorageClass:=IMAGE_SYM_CLASS_STATIC;
+  st.NumAuxSymbol:=0;
+  {$IFDEF ENDIAN_BIG}
+  st.Value:=SwapEndian(st.Value);
+  st.SectionNumber:=SwapEndian(st.SectionNumber);
+  st._type:=SwapEndian(st._type);
+  st.StorageClass:=SwapEndian(st.StorageClass);
+  st.NumAuxSymbol:=SwapEndian(st.NumAuxSymbol);
+  {$ENDIF}
+  aStream.WriteBuffer(st,sizeof(st));
+end;
+
+procedure TCoffResourceWriter.WriteEmptyCoffStringTable(aStream : TStream);
+var lw : longword;
+begin
+  lw:=4;
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  aStream.WriteBuffer(lw,4);
+end;
+
+procedure TCoffResourceWriter.FixCoffHeader(aStream: TStream);
+var hdr : TCoffHeader;
+    oldpos : int64;
+begin
+
+  oldpos:=aStream.Position;
+  aStream.Position:=0;
+
+  case fMachineType of
+    cmti386  : hdr.machine:=IMAGE_FILE_MACHINE_I386;
+    cmtarm   : hdr.machine:=IMAGE_FILE_MACHINE_ARM;
+    cmtx8664 : hdr.machine:=IMAGE_FILE_MACHINE_AMD64;
+  end;
+  hdr.numsects:=1;
+  hdr.timestamp:=0; //DateTimeToTimeT(now);   //we need a crossplatform way to have it UTC
+  hdr.symtableptr:=fSymTablePtr;
+  hdr.symnum:=1;
+  hdr.opthdrsize:=0;
+  hdr.characteristics:=IMAGE_FILE_32BIT_MACHINE or IMAGE_FILE_LINE_NUMS_STRIPPED;
+  {$IFDEF ENDIAN_BIG}
+  hdr.machine:=SwapEndian(hdr.machine);
+  hdr.numsects:=SwapEndian(hdr.numsects);
+  hdr.timestamp:=SwapEndian(hdr.timestamp);
+  hdr.symtableptr:=SwapEndian(hdr.symtableptr);
+  hdr.symnum:=SwapEndian(hdr.symnum);
+  hdr.opthdrsize:=SwapEndian(hdr.opthdrsize);
+  hdr.characteristics:=SwapEndian(hdr.characteristics);
+  {$ENDIF}
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+  
+  aStream.Position:=oldpos;
+
+end;
+
+procedure TCoffResourceWriter.FixSectionHeader(aStream : TStream);
+var hdr : TCoffSectionHeader;
+    oldpos : int64;
+begin
+  oldpos:=aStream.Position;
+  aStream.Position:=sizeof(TCoffHeader);
+
+  hdr.Name:=RSRCSectName;
+  hdr.VirtualSize:=0;
+  hdr.VirtualAddress:=0;
+  hdr.SizeOfRawData:=fResDataEntryCurrentRVA;
+  hdr.PointerToRawData:=sizeof(TCoffHeader)+sizeof(TCoffSectionHeader);
+  hdr.PointerToRelocations:=fRelocations.StartAddress;
+  hdr.PointerToLineNumbers:=0;
+  hdr.NumberOfRelocations:=fRelocations.Count;
+  hdr.NumberOfLineNumbers:=0;
+  hdr.Characteristics:=IMAGE_SCN_CNT_INITIALIZED_DATA or IMAGE_SCN_MEM_READ or
+                       IMAGE_SCN_MEM_WRITE;
+  {$IFDEF ENDIAN_BIG}
+  hdr.VirtualSize:=SwapEndian(hdr.VirtualSize);
+  hdr.VirtualAddress:=SwapEndian(hdr.VirtualAddress);
+  hdr.SizeOfRawData:=SwapEndian(hdr.SizeOfRawData);
+  hdr.PointerToRawData:=SwapEndian(hdr.PointerToRawData);
+  hdr.PointerToRelocations:=SwapEndian(hdr.PointerToRelocations);
+  hdr.PointerToLineNumbers:=SwapEndian(hdr.PointerToLineNumbers);
+  hdr.NumberOfRelocations:=SwapEndian(hdr.NumberOfRelocations);
+  hdr.NumberOfLineNumbers:=SwapEndian(hdr.NumberOfLineNumbers);
+  hdr.Characteristics:=SwapEndian(hdr.Characteristics);
+  {$ENDIF}
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+
+  aStream.Position:=oldpos;
+end;
+
+function TCoffResourceWriter.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TCoffResourceWriter.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+function TCoffResourceWriter.NextAlignedDword(aValue: longword): longword;
+var topad : longword;
+begin
+  Result:=aValue;
+  topad:=4-(aValue mod 4);
+  if topad<>4 then inc(Result,topad);
+end;
+
+procedure TCoffResourceWriter.SetNodeStringRVA(aNode: TResourceTreeNode);
+begin
+  if aNode.Desc.DescType=dtID then exit;
+  aNode.NameRVA:=fResStringTable.CurrRVA;
+  fResStringTable.Add(aNode.Desc.Name);
+end;
+
+function TCoffResourceWriter.PrescanNode(aNode: TResourceTreeNode
+  ): longword;
+var i : integer;
+    currva : longword;
+    subnode : TResourceTreeNode;
+begin
+  currva:=aNode.SubDirRVA;
+  SetNodeStringRVA(aNode);
+  if aNode.IsLeaf then
+  begin
+    Result:=currva;
+    exit;
+  end;
+  inc(currva,sizeof(TResDirTable));
+  inc(currva,(aNode.NamedCount+aNode.IDCount)*sizeof(TResDirEntry));
+  for i:=0 to aNode.NamedCount-1 do
+  begin
+    subnode:=aNode.NamedEntries[i];
+    subnode.SubDirRVA:=currva;
+    currva:=PrescanNode(subnode);
+  end;
+  for i:=0 to aNode.IDCount-1 do
+  begin
+    subnode:=aNode.IDEntries[i];
+    subnode.SubDirRVA:=currva;
+    currva:=PrescanNode(subnode);
+  end;
+  Result:=currva;
+end;
+
+procedure TCoffResourceWriter.PrescanResourceTree;
+begin
+  fRoot.SubDirRVA:=0;
+  fResStringTable.Clear;
+  fResStringTable.StartRVA:=PrescanNode(fRoot);
+end;
+
+procedure TCoffResourceWriter.Write(aResources: TResources; aStream: TStream);
+begin
+  WriteEmptyCoffHeader(aStream);
+  WriteEmptySectionHeader(aStream);
+  fRoot:=TRootResTreeNode(GetTree(aResources));
+  PrescanResourceTree;
+  WriteResDirTables(aStream);
+  WriteResStringTable(aStream);
+  WriteResDataEntries(aStream);
+  WriteRawData(aStream);
+  WriteRelocations(aStream);
+  WriteSymbolTable(aStream);
+  WriteEmptyCoffStringTable(aStream);
+  FixCoffHeader(aStream);
+  FixSectionHeader(aStream);
+end;
+
+constructor TCoffResourceWriter.Create;
+begin
+  fExtensions:='.o .obj';
+  fDescription:='COFF resource writer';
+  fMachineType:=cmti386;
+  fRoot:=nil;
+  fResStringTable:=TResourceStringTable.Create;
+  fResDataEntryCurrentRVA:=0;
+  fSymTablePtr:=0;
+  fRelocations:=TCoffRelocations.Create;
+end;
+
+destructor TCoffResourceWriter.Destroy;
+begin
+  fResStringTable.Free;
+  fRelocations.Free;
+end;
+
+{ TResourceStringTable }
+
+function TResourceStringTable.GetString(index: integer): string;
+begin
+  Result:=fList[index];
+end;
+
+function TResourceStringTable.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+procedure TResourceStringTable.SetStartRVA(aValue: longword);
+var topad : longword;
+begin
+  fStartRVA:=aValue;
+  inc(fCurrRva,fStartRVA);
+  fEndRVA:=fCurrRVA;
+  topad:=4-(fEndRVA mod 4);
+  if topad<>4 then inc(fEndRVA,topad);
+end;
+
+constructor TResourceStringTable.Create;
+begin
+  fList:=TStringList.Create;
+  fCurrRVA:=0;
+  fStartRVA:=0;
+  fEndRVA:=0;
+end;
+
+destructor TResourceStringTable.Destroy;
+begin
+  fList.Free;
+end;
+
+procedure TResourceStringTable.Add(s: string);
+begin
+  fList.Add(s);
+  inc(fCurrRVA,(length(s)+1)*2);
+end;
+
+procedure TResourceStringTable.Clear;
+begin
+  fList.Clear;
+  fCurrRVA:=0;
+  fStartRVA:=0;
+  fEndRVA:=0;
+end;
+
+{ TCoffRelocations }
+
+function TCoffRelocations.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+function TCoffRelocations.GetRelocation(index: integer): PCoffRelocation;
+begin
+  Result:=PCoffRelocation(fList[index]);
+end;
+
+constructor TCoffRelocations.Create;
+begin
+  fList:=TFPList.Create;
+  fStartAddress:=0;
+end;
+
+destructor TCoffRelocations.Destroy;
+begin
+  Clear;
+  fList.Free;
+end;
+
+procedure TCoffRelocations.Add(aAddress: longword; aType: word);
+var p : PCoffRelocation;
+begin
+  p:=GetMem(sizeof(TCoffRelocation));
+  p^.VirtualAddress:=aAddress;
+  p^.SymTableIndex:=0;
+  p^._type:=aType;
+  fList.Add(p);
+end;
+
+procedure TCoffRelocations.Clear;
+var i : integer;
+begin
+  for i:=0 to fList.Count-1 do
+    Freemem(PCoffRelocation(fList[i]));
+  fList.Clear;
+end;
+
+initialization
+  TResources.RegisterWriter('.o',TCoffResourceWriter);
+  TResources.RegisterWriter('.obj',TCoffResourceWriter);
+
+end.

+ 238 - 0
packages/fcl-res/src/dfmreader.pp

@@ -0,0 +1,238 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for DFM files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit dfmreader;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+
+type
+
+  { TDfmResourceReader }
+
+  TDfmResourceReader = class (TAbstractResourceReader)
+  private
+    fExtensions : string;
+    fDescription : string;
+    fLine : string;
+    fLinePos : integer;
+    fObjectName : string;
+    dummyType : TResourceDesc;
+    dummyName : TResourceDesc;
+    fIsBinary : boolean;
+    function IsAlpha : boolean;
+    function IsNum : boolean;
+    function IsAlphaNum : boolean;
+    function IsSpace : boolean;
+    procedure SkipSpaces;
+    function GetIdent : string;
+    procedure ReadLine(aStream : TStream);
+    
+    function CheckTextDfm(aStream : TStream) : boolean;
+    function CheckBinDfm(aStream : TStream) : boolean;
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Load(aResources : TResources; aStream : TStream); override;
+    function CheckMagic(aStream : TStream) : boolean; override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+  end;
+
+
+implementation
+
+uses
+  resdatastream, resfactory;
+
+type
+  TSignature = array[0..3] of char;
+
+const
+  FilerSignature = 'TPF0';
+
+{ TDfmResourceReader }
+
+function TDfmResourceReader.IsAlpha: boolean;
+begin
+  Result:=pchar(fLine)[fLinePos] in ['_','A'..'Z','a'..'z'];
+end;
+
+function TDfmResourceReader.IsNum: boolean;
+begin
+  Result:=pchar(fLine)[fLinePos] in ['0'..'9'];
+end;
+
+function TDfmResourceReader.IsAlphaNum: boolean;
+begin
+  Result:=IsAlpha or IsNum;
+end;
+
+function TDfmResourceReader.IsSpace: boolean;
+const TAB = #9;
+begin
+  Result:=pchar(fLine)[fLinePos] in [' ',TAB];
+end;
+
+procedure TDfmResourceReader.SkipSpaces;
+begin
+  while IsSpace do inc(fLinePos);
+end;
+
+function TDfmResourceReader.GetIdent: string;
+begin
+  Result:='';
+  SkipSpaces;
+  if not IsAlpha then exit;
+  while IsAlphaNum do
+  begin
+    Result:=Result+pchar(fLine)[fLinePos];
+    inc(fLinePos);
+  end;
+end;
+
+procedure TDfmResourceReader.ReadLine(aStream : TStream);
+const CR = #13;
+      LF = #10;
+var c : char;
+begin
+  fLine:='';
+  
+  repeat
+    aStream.ReadBuffer(c,1);
+    if not (c in [CR,LF,#0]) then
+      fLine:=fLine+c;
+  until c in [CR,LF,#0];
+  fLinePos:=0;
+end;
+
+(*should be:  object Name: Type  or inherited Name: Type*)
+function TDfmResourceReader.CheckTextDfm(aStream: TStream): boolean;
+var tmp : string;
+begin
+  Result:=false;
+  fLine:='';
+  while fLine='' do
+    ReadLine(aStream);
+  tmp:=lowercase(GetIdent);
+  if (tmp <> 'object') and (tmp<>'inherited') then exit;
+  if GetIdent='' then exit;
+  SkipSpaces;
+  if pchar(fLine)[fLinePos]<>':' then exit;
+  inc(fLinePos);
+  SkipSpaces;
+  fObjectName:=UpperCase(GetIdent);
+  if fObjectName='' then exit;
+  Result:=true;
+  fIsBinary:=false;
+end;
+
+function TDfmResourceReader.CheckBinDfm(aStream: TStream): boolean;
+var s : shortstring;
+    b : byte;
+begin
+  aStream.ReadBuffer(b,1);
+  s[0]:=Chr(b);
+  aStream.ReadBuffer(s[1],b);
+  fObjectName:=UpperCase(s);
+  Result:=fObjectName<>'';
+  fIsBinary:=true;
+end;
+
+function TDfmResourceReader.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TDfmResourceReader.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TDfmResourceReader.Load(aResources: TResources; aStream: TStream);
+var aRes : TAbstractResource;
+    RawData : TResourceDataStream;
+begin
+  if not CheckMagic(aStream) then
+    raise EResourceReaderWrongFormatException.Create('');
+
+  dummyName.Name:=fObjectName;
+  aRes:=TResourceFactory.CreateResource(dummyType,dummyName);
+  if fIsBinary then
+  begin
+    SetDataSize(aRes,aStream.Size-aStream.Position);
+    SetDataOffset(aRes,aStream.Position);
+    RawData:=TResourceDataStream.Create(aStream,aRes,aRes.DataSize,TCachedResourceDataStream);
+    SetRawData(aRes,RawData);
+  end
+  else
+    ObjectTextToBinary(aStream,aRes.RawData);
+    
+  try
+    aResources.Add(aRes);
+  except
+    on e : EResourceDuplicateException do
+    begin
+      aRes.Free;
+      raise;
+    end;
+  end;
+end;
+
+function TDfmResourceReader.CheckMagic(aStream: TStream): boolean;
+var sig : TSignature;
+    orig : int64;
+begin
+  orig:=aStream.Position;
+  aStream.ReadBuffer(sig,4);
+  if sig=FilerSignature then Result:=CheckBinDfm(aStream)
+  else
+  begin
+    aStream.Seek(-4,soFromCurrent);
+    Result:=CheckTextDfm(aStream);
+  end;
+  aStream.Position:=orig;
+end;
+
+constructor TDfmResourceReader.Create;
+begin
+  fExtensions:='.dfm .xfm .lfm';
+  fDescription:='DFM resource reader';
+  fLine:='';
+  fLinePos:=0;
+  fObjectName:='';
+  fIsBinary:=false;
+  dummyType:=TResourceDesc.Create;
+  dummyType.ID:=RT_RCDATA;
+  dummyName:=TResourceDesc.Create;
+end;
+
+destructor TDfmResourceReader.Destroy;
+begin
+  dummyType.Free;
+  dummyName.Free;
+end;
+
+initialization
+  TResources.RegisterReader('.dfm',TDfmResourceReader);
+  TResources.RegisterReader('.xfm',TDfmResourceReader);
+  TResources.RegisterReader('.lfm',TDfmResourceReader);
+
+end.

+ 144 - 0
packages/fcl-res/src/elfconsts.pp

@@ -0,0 +1,144 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Constants used by ELF resource reader and writer
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit elfconsts;
+
+{$MODE OBJFPC}
+
+interface
+
+type
+  TElfMachineType = (emtnone, emtsparc, emti386, emtm68k, emtppc, emtppc64,
+                     emtarm, emtarmeb, emtia64, emtx86_64, emtalpha);
+const
+  ELFMAGIC     = chr($7f)+'ELF';
+
+  //elf class
+  ELFCLASSNONE = 0;
+  ELFCLASS32   = 1;
+  ELFCLASS64   = 2;
+
+  //byte order
+  ELFDATANONE  = 0;
+  ELFDATA2LSB  = 1;
+  ELFDATA2MSB  = 2;
+
+  //elf version
+  EV_NONE      = 0;
+  EV_CURRENT   = 1;
+
+  //OS ABI
+  ELFOSABI_NONE    =  0;  // UNIX System V ABI
+  ELFOSABI_LINUX   =  3;
+  ELFOSABI_FREEBSD =  9;
+  ELFOSABI_ARM     = 97;
+
+  //object file type
+  ET_NONE      = 0;
+  ET_REL       = 1;
+  ET_EXEC      = 2;
+  ET_DYN       = 3;
+  ET_CORE      = 4;
+  ET_LOOS      = $fe00; //os-specific
+  ET_HIOS      = $feff;
+  ET_LOPROC    = $ff00; //processor-specific
+  ET_HIPROC    = $ffff;
+
+  //machine type
+  EM_NONE        =  0;
+  EM_SPARC       =  2;
+  EM_386         =  3;
+  EM_68K         =  4;
+  EM_PPC         = 20;
+  EM_PPC64       = 21;
+  EM_ARM         = 40;
+//  EM_OLD_ALPHA       = 41;
+  EM_IA_64       = 50;
+  EM_X86_64      = 62;
+  EM_ALPHA       = $9026; //unofficial, but used by gnu toolchain
+  
+  //machine-specific flags
+  EF_IA_64_ABI64 = $10;  //wow, this is really a 64-bit object file!
+
+  //section type
+  SHT_NULL     =  0;
+  SHT_PROGBITS =  1;
+  SHT_SYMTAB   =  2;
+  SHT_STRTAB   =  3;
+  SHT_RELA     =  4;
+  SHT_HASH     =  5;
+  SHT_DYNAMIC  =  6;
+  SHT_NOTE     =  7;
+  SHT_NOBITS   =  8;
+  SHT_REL      =  9;
+  SHT_SHLIB    = 10;
+  SHT_DYNSYM   = 11;
+  SHT_LOPROC   = $70000000;
+  SHT_HIPROC   = $7fffffff;
+  SHT_LOOS     = $80000000;
+  SHT_HIOS     = $ffffffff;
+
+  //section attribute flags
+  SHF_WRITE     =         1;
+  SHF_ALLOC     =         2;
+  SHF_EXECINSTR =         4;
+  SHF_MASKOS    = $0f000000;
+  SHF_MASKPROC  = $f0000000;
+  
+  //symbol bindings
+  STB_LOCAL  =  0;
+  STB_GLOBAL =  1;
+  STB_WEAK   =  2;
+  STB_LOOS   = 10;
+  STB_HIOS   = 12;
+  STB_LOPROC = 13;
+  STB_HIPROC = 15;
+  
+  //symbol types
+  STT_NOTYPE         =  0;
+  STT_OBJECT         =  1;
+  STT_FUNC           =  2;
+  STT_SECTION        =  3;
+  STT_FILE           =  4;
+  STT_COMMON         =  5;
+  STT_TLS            =  6;
+  STT_LOOS           = 10;
+  STT_HIOS           = 12;
+  STT_LOPROC         = 13;
+  STT_SPARC_REGISTER = 13;
+  STT_HIPROC         = 15;
+
+  //direct, natural-size relocation types
+  R_386_32        =   1;
+  R_x86_64_64     =   1;
+  R_PPC_ADDR32    =   1;
+  R_PPC64_ADDR64  =  38;
+  R_ARM_ABS32     =   2;
+  R_68K_32        =   1;
+  R_SPARC_32      =   3;
+  R_ALPHA_REFQUAD =   2;
+  R_IA64_DIR64LSB = $27;
+
+
+  //fpc resource constants
+  RsrcSectName    = 'fpc.resources';
+  HandlesSectName = 'fpc.reshandles';
+  
+  RSRCSECT_IDX = 1;
+  HANDLESECT_IDX = 2;
+
+implementation
+
+end.

+ 67 - 0
packages/fcl-res/src/elfdefaulttarget.inc

@@ -0,0 +1,67 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Default ELF target parameters
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+  fMachineType:=emtnone;
+  {$IFDEF CPUI386}
+  fMachineType:=emti386;
+  {$ENDIF}
+  {$IFDEF CPUX86_64}
+  fMachineType:=emtx86_64;
+  {$ENDIF}
+  {$IFDEF CPUPOWERPC32}
+  fMachineType:=emtppc;;
+  {$ENDIF}
+  {$IFDEF CPUPOWERPC64}
+  fMachineType:=emtppc64;;
+  {$ENDIF}
+  {$IFDEF CPUARM}
+    {$IFDEF ENDIAN_LITTLE}
+    fMachineType:=emtarm;
+    {$ELSE}
+    fMachineType:=emtarmeb;
+    {$ENDIF}
+  {$ENDIF}
+  {$IFDEF CPU68K}
+  fMachineType:=emtm68k;
+  {$ENDIF}
+  {$IFDEF CPUSPARC}
+  fMachineType:=emtsparc;
+  {$ENDIF}
+  {$IFDEF CPUALPHA}
+  fMachineType:=emtalpha;
+  {$ENDIF}
+  {$IFDEF CPUIA64}
+  fMachineType:=emtia64;
+  {$ENDIF}
+
+  fBits:=ELFCLASSNONE;
+  {$IFDEF CPU32}
+  fBits:=ELFCLASS32;
+  {$ENDIF}
+  {$IFDEF CPU64}
+  fBits:=ELFCLASS64;
+  {$ENDIF}
+
+  fNativeOrder:=ELFDATANONE;
+  {$IFDEF ENDIAN_LITTLE}
+  fNativeOrder:=ELFDATA2LSB;
+  {$ENDIF}
+  {$IFDEF ENDIAN_BIG}
+  fNativeOrder:=ELFDATA2MSB;
+  {$ENDIF}
+  fOrder:=fNativeOrder;
+
+  fOppositeEndianess:=false;
+

+ 316 - 0
packages/fcl-res/src/elfreader.pp

@@ -0,0 +1,316 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for ELF files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit elfreader;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, elfconsts, elftypes;
+
+type
+  EElfResourceReaderException = class(EResourceReaderException);
+  EElfResourceReaderUnknownClassException = class(EElfResourceReaderException);
+  EElfResourceReaderUnknownVersionException = class(EElfResourceReaderException);
+  EElfResourceReaderNoSectionsException = class(EElfResourceReaderException);
+  EElfResourceReaderNoStringTableException = class(EElfResourceReaderException);
+
+type
+
+  { TElfResourceReader }
+
+  TElfResourceReader = class (TAbstractResourceReader)
+  private
+    fDescription: string;
+    fExtensions: string;
+    fMachineType : TElfMachineType;
+    fOrder : byte;
+    fBits : byte;
+    fNativeOrder : integer;
+    fOppositeEndianess : boolean;
+    procedure SetDefaultTarget;
+    function ReadElfIdent(aStream : TStream) : boolean;
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Load(aResources : TResources; aStream : TStream); override;
+    function CheckMagic(aStream : TStream) : boolean; override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    property MachineType : TElfMachineType read fMachineType;
+  end;
+
+implementation
+
+uses resdatastream, resfactory, resourcetree, strtable, fpcrestypes;
+
+type
+
+  { TAbstractElfSubReader }
+
+  TAbstractElfSubReader = class
+  private
+  protected
+    fParent : TElfResourceReader;
+    fRoot : TRootResTreeNode;
+    fOppositeEndianess : boolean;
+    fMachineType : integer;
+    fStringTable : TObjectStringTable;
+    fSectIdx : integer;
+    fRelSectIdx : integer;
+    dummyDesc : TResourceDesc;
+    fNeedsReloc : boolean;
+
+    function FindSection(const aName : string) : integer; virtual; abstract;
+    function FindResSection : boolean;
+    function ReadString(aStream : TStream; aPos : longword) : string;
+    procedure ReadNode(aStream : TStream; aParent : TResourceTreeNode;
+      aResources : TResources; named : boolean); virtual; abstract;
+    procedure ReadResData(aStream : TStream; aNode : TResourceTreeNode;
+      aResources : TResources; datasize : longword);
+    procedure LoadResources(aResources : TResources; aStream : TStream);
+    procedure Load(aResources : TResources; aStream : TStream); virtual; abstract;
+  public
+    constructor Create(aParent : TElfResourceReader; const aOppositeEndianess : boolean);
+    destructor Destroy; override;
+    property MachineType : integer read fMachineType;
+  end;
+  
+(*
+Almost all differences in 32 and 64 bit elf files lie in record sizes.
+Generics don't work with record types, so use macros to do this task
+(uglier, but should be the same)
+*)
+
+{$MACRO ON}
+
+//Define TElf32RelocTable and TElf32SubReader
+
+{$DEFINE _TElfRelocTable_:=TElf32RelocTable}
+{$DEFINE _TPElfRela_:=PElf32Rela}
+{$DEFINE _TElfRela_:=TElf32Rela}
+{$DEFINE _Tword_:=longword}
+{$DEFINE _TElfSubReader_:=TElf32SubReader}
+{$DEFINE _TElfHdr_:=TElf32Hdr}
+{$DEFINE _TElfSectHdr_:=TElf32SectHdr}
+{$DEFINE _TResHdr_:=TResHdr32}
+{$DEFINE _TResInfoNode_:=TResInfoNode32}
+{$INCLUDE elfsubreader.inc}
+
+
+//Define TElf64RelocTable and TElf64SubReader
+
+{$DEFINE _TElfRelocTable_:=TElf64RelocTable}
+{$DEFINE _TPElfRela_:=PElf64Rela}
+{$DEFINE _TElfRela_:=TElf64Rela}
+{$DEFINE _Tword_:=qword}
+{$DEFINE _TElfSubReader_:=TElf64SubReader}
+{$DEFINE _TElfHdr_:=TElf64Hdr}
+{$DEFINE _TElfSectHdr_:=TElf64SectHdr}
+{$DEFINE _TResHdr_:=TResHdr64}
+{$DEFINE _TResInfoNode_:=TResInfoNode64}
+{$INCLUDE elfsubreader.inc}
+
+
+//Clean all this stuff...
+
+{$UNDEF _TElfRelocTable_}
+{$UNDEF _TPElfRela_}
+{$UNDEF _TElfRela_}
+{$UNDEF _Tword_}
+{$UNDEF _TElfSubReader_}
+{$UNDEF _TElfHdr_}
+{$UNDEF _TElfSectHdr_}
+{$UNDEF _TResHdr_}
+{$UNDEF _TResInfoNode_}
+
+
+{ TAbstractElfSubReader }
+
+function TAbstractElfSubReader.FindResSection : boolean;
+begin
+  fSectIdx:=FindSection(RsrcSectName);
+  Result:=fSectIdx<>-1;
+  if not Result then exit;
+  if fNeedsReloc then
+  begin
+    fRelSectIdx:=FindSection('.rela'+RsrcSectName);
+    Result:=fRelSectIdx<>-1;
+  end;
+end;
+
+function TAbstractElfSubReader.ReadString(aStream: TStream; aPos: longword
+  ): string;
+var oldpos : int64;
+    c : char;
+    maxleft : int64;
+begin
+  Result:='';
+  oldpos:=aStream.Position;
+  aStream.Position:=aPos;
+  aStream.ReadBuffer(c,1);
+  maxleft:=aStream.Size-aStream.Position;
+  while (c<>#0) and (maxleft>=0) do
+  begin
+    Result:=Result+c;
+    aStream.ReadBuffer(c,1);
+    dec(maxleft);
+  end;
+  aStream.Position:=oldpos;
+end;
+
+procedure TAbstractElfSubReader.ReadResData(aStream: TStream;
+  aNode: TResourceTreeNode; aResources: TResources; datasize: longword);
+var aRes : TAbstractResource;
+    RawData : TResourceDataStream;
+begin
+  aRes:=aNode.CreateResource;
+  if aRes=nil then
+    raise EResourceDuplicateException.CreateFmt(SResDuplicate,[
+      aNode.Data._Type.Name,aNode.Data.Name.Name,aNode.Data.LangID]);
+  fParent.SetDataSize(aRes,datasize);
+  fParent.SetDataOffset(aRes,aStream.Position);
+  RawData:=TResourceDataStream.Create(aStream,aRes,aRes.DataSize,TCachedResourceDataStream);
+  fParent.SetRawData(aRes,RawData);
+  fParent.AddNoTree(aResources,aRes);
+end;
+
+procedure TAbstractElfSubReader.LoadResources(aResources: TResources;
+  aStream: TStream);
+begin
+  fRoot:=TRootResTreeNode(fParent.GetTree(aResources));
+  ReadNode(aStream,nil,aResources,false);
+end;
+
+constructor TAbstractElfSubReader.Create(aParent : TElfResourceReader;
+  const aOppositeEndianess: boolean);
+begin
+  fParent:=aParent;
+  fOppositeEndianess:=aOppositeEndianess;
+  fMachineType:=EM_386;
+  fSectIdx:=0;
+  fRelSectIdx:=0;
+  fStringTable:=nil;
+  dummyDesc:=TResourceDesc.Create;
+  fRoot:=nil;
+  fNeedsReloc:=false;
+end;
+
+destructor TAbstractElfSubReader.Destroy;
+begin
+  if fStringTable<>nil then fStringTable.Free;
+  dummyDesc.Free;
+end;
+
+{ TElfResourceReader }
+
+procedure TElfResourceReader.SetDefaultTarget;
+begin
+  {$INCLUDE elfdefaulttarget.inc}
+end;
+
+function TElfResourceReader.ReadElfIdent(aStream : TStream) : boolean;
+var ident : TElfIdent;
+begin
+  Result:=false;
+
+  try
+    aStream.ReadBuffer(ident,sizeof(ident));
+  except
+    on e : EReadError do exit;
+  end;
+
+  if ident.Magic<>ELFMAGIC then exit;
+  fBits:=ident.ElfClass;
+  fOppositeEndianess:=ident.ElfData<>fNativeOrder;
+  fOrder:=ident.ElfData;
+  if ident.ElfVersion<>EV_CURRENT then exit;
+
+  Result:=true;
+end;
+
+function TElfResourceReader.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TElfResourceReader.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TElfResourceReader.Load(aResources: TResources; aStream: TStream);
+var subreader : TAbstractElfSubReader;
+begin
+  if not ReadElfIdent(aStream) then
+    raise EResourceReaderWrongFormatException.Create('');
+  case fBits of
+    ELFCLASS32 : subreader:=TElf32SubReader.Create(self,fOppositeEndianess);
+    ELFCLASS64 : subreader:=TElf64SubReader.Create(self,fOppositeEndianess)
+  else
+    raise EElfResourceReaderUnknownClassException.Create('');
+  end;
+  try
+    try
+      subreader.Load(aResources,aStream);
+    except
+      on e : EReadError do
+        raise EResourceReaderUnexpectedEndOfStreamException.Create('');
+    end;
+    case subreader.MachineType of
+      EM_SPARC  : fMachineType:=emtsparc;
+      EM_386    : fMachineType:=emti386;
+      EM_68K    : fMachineType:=emtm68k;
+      EM_PPC    : fMachineType:=emtppc;
+      EM_PPC64  : fMachineType:=emtppc64;
+      EM_ARM    : if fOrder=ELFDATA2LSB then
+                    fMachineType:=emtarm
+                  else
+                    fMachineType:=emtarmeb;
+      EM_ALPHA  : fMachineType:=emtalpha;
+      EM_IA_64  : fMachineType:=emtia64;
+      EM_X86_64 : fMachineType:=emtx86_64;
+    end;
+  finally
+    subreader.Free;
+  end;
+end;
+
+function TElfResourceReader.CheckMagic(aStream: TStream): boolean;
+begin
+  Result:=ReadElfIdent(aStream);
+end;
+
+constructor TElfResourceReader.Create;
+begin
+  fExtensions:='.o .or';
+  fDescription:='ELF resource reader';
+  SetDefaultTarget;
+end;
+
+destructor TElfResourceReader.Destroy;
+begin
+
+end;
+
+initialization
+  TResources.RegisterReader('.o',TElfResourceReader);
+  TResources.RegisterReader('.or',TElfResourceReader);
+  TResources.RegisterReader('',TElfResourceReader);
+
+end.

+ 282 - 0
packages/fcl-res/src/elfsubreader.inc

@@ -0,0 +1,282 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for ELF files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+type
+
+(*
+  generic TElfRelocTable<_TPElfRela_,_TElfRela_,_TElfSectHdr_,_Tword_> = class
+  ...
+  TElf32RelocTable = specialize TElfRelocTable<PElf32Rela,TElf32Rela,
+                                               TElf32SectHdr,longword>;
+  TElf64RelocTable = specialize TElfRelocTable<PElf64Rela,TElf64Rela,
+                                               TElf64SectHdr,qword>;
+*)
+
+  _TElfRelocTable_= class
+  private
+    fList : _TPElfRela_;
+    fCount : integer;
+  protected
+  public
+    constructor Create(aStream : TStream; const aSectHdr : _TElfSectHdr_; const aOppositeEndianess : boolean);
+    destructor Destroy; override;
+    function Get(aOffset : _Tword_) : _Tword_;
+  end;
+
+(*
+  generic TElfSubReader<_TElfHdr_,_TElfSectHdr_,_TResHdr_,_TResInfoNode_> = class
+  ...
+  TElf32SubReader = specialize TElfSubReader<TElf32Hdr,TElf32SectHdr,TResHdr32,
+    TResInfoNode32>;
+  TElf64SubReader = specialize TElfSubReader<TElf64Hdr,TElf64SectHdr,TResHdr64,
+    TResInfoNode64>;
+*)
+
+  { _TElfSubReader_ }
+
+  _TElfSubReader_ = class(TAbstractElfSubReader)
+  private
+    fElfHdr : _TElfHdr_;
+    fSectHeaders : array of _TElfSectHdr_;
+    fResHdr : _TResHdr_;
+    fRelocations : _TElfRelocTable_;
+    procedure ReadElfHeader(aStream : TStream);
+    procedure ReadSectionHeaders(aStream : TStream);
+    procedure ReadStringTable(aStream : TStream);
+    function FindSection(const aName : string) : integer; override;
+    procedure ReadRelocations(aStream : TStream);
+    procedure ReadResHeader(aStream : TStream);
+    procedure ReadNode(aStream : TStream; aParent : TResourceTreeNode;
+      aResources : TResources; named : boolean); override;
+  protected
+    procedure Load(aResources : TResources; aStream : TStream); override;
+  public
+  end;
+
+
+constructor _TElfRelocTable_.Create(aStream : TStream;
+  const aSectHdr : _TElfSectHdr_; const aOppositeEndianess : boolean);
+var i : integer;
+begin
+  aStream.Position:=aSectHdr.offset;
+  fList:=GetMem(aSectHdr.size);
+  fCount:=aSectHdr.size div sizeof(_TElfRela_);
+  aStream.ReadBuffer(fList[0],aSectHdr.size);
+  if aOppositeEndianess then
+    for i:=0 to fCount-1 do
+    begin
+      fList[i].Offset:=SwapEndian(fList[i].Offset);
+      fList[i].Info:=SwapEndian(fList[i].Info);
+      fList[i].addend:=SwapEndian(fList[i].addend);
+    end;
+end;
+
+destructor _TElfRelocTable_.Destroy;
+begin
+  FreeMem(fList);
+end;
+
+function _TElfRelocTable_.Get(aOffset : _Tword_) : _Tword_;
+var l,r,pivot : integer;
+begin
+  Result:=0;
+  if fCount=0 then exit;
+  l:=0; r:=fCount-1;
+  while l<=r do
+  begin
+    pivot:=(l+r) div 2;
+    if fList[pivot].Offset<aOffset then l:=pivot+1
+    else if fList[pivot].Offset>aOffset then r:=pivot-1
+    else
+    begin
+      Result:=fList[pivot].Addend;
+      exit;
+    end;
+  end;
+end;
+
+
+procedure _TElfSubReader_.ReadElfHeader(aStream: TStream);
+begin
+  aStream.ReadBuffer(fElfHdr,sizeof(fElfHdr));
+  if fOppositeEndianess then
+  begin
+    fElfHdr._Type:=SwapEndian(fElfHdr._Type);
+    fElfHdr.Machine:=SwapEndian(fElfHdr.Machine);
+    fElfHdr.Version:=SwapEndian(fElfHdr.Version);
+    fElfHdr.Entry:=SwapEndian(fElfHdr.Entry);
+    fElfHdr.ProgHdrOffset:=SwapEndian(fElfHdr.ProgHdrOffset);
+    fElfHdr.SectHdrOffset:=SwapEndian(fElfHdr.SectHdrOffset);
+    fElfHdr.Flags:=SwapEndian(fElfHdr.Flags);
+    fElfHdr.HdrSize:=SwapEndian(fElfHdr.HdrSize);
+    fElfHdr.ProgHdrEntrySize:=SwapEndian(fElfHdr.ProgHdrEntrySize);
+    fElfHdr.ProgHdrNum:=SwapEndian(fElfHdr.ProgHdrNum);
+    fElfHdr.SectHdrEntrySize:=SwapEndian(fElfHdr.SectHdrEntrySize);
+    fElfHdr.SectHdrNum:=SwapEndian(fElfHdr.SectHdrNum);
+    fElfHdr.NameTableIndex:=SwapEndian(fElfHdr.NameTableIndex);
+  end;
+  fMachineType:=fElfHdr.Machine;
+  if fElfHdr.Version<>EV_CURRENT then
+    raise EElfResourceReaderUnknownVersionException.Create('');
+  if fElfHdr.SectHdrNum=0 then
+    raise EElfResourceReaderNoSectionsException.Create('');
+  fNeedsReloc:=(fElfHdr._Type = ET_REL);
+  if fNeedsReloc then
+    case fElfHdr.Machine of
+      EM_386    : fNeedsReloc:=false;
+      EM_PPC    : ;
+      EM_ARM    : fNeedsReloc:=false;
+      EM_68K    : ;
+      EM_SPARC  : ;
+      EM_X86_64 : ;
+      EM_PPC64  : ;
+      EM_ALPHA  : ;
+      EM_IA_64  : ;
+    end;
+end;
+
+procedure _TElfSubReader_.ReadSectionHeaders(aStream: TStream);
+var i : integer;
+    delta : integer;
+begin
+  setlength(fSectHeaders,fElfHdr.SectHdrNum);
+  delta:=fElfHdr.SectHdrEntrySize-sizeof(_TElfSectHdr_);
+  aStream.Position:=fElfHdr.SectHdrOffset;
+  for i:=0 to fElfHdr.SectHdrNum-1 do
+  begin
+    aStream.ReadBuffer(fSectHeaders[i],sizeof(fSectHeaders[i]));
+    if delta>0 then aStream.Seek(delta,soFromCurrent);
+    if fOppositeEndianess then
+    begin
+      fSectHeaders[i].NameIdx:=SwapEndian(fSectHeaders[i].NameIdx);
+      fSectHeaders[i]._Type:=SwapEndian(fSectHeaders[i]._Type);
+      fSectHeaders[i].Flags:=SwapEndian(fSectHeaders[i].Flags);
+      fSectHeaders[i].Address:=SwapEndian(fSectHeaders[i].Address);
+      fSectHeaders[i].Offset:=SwapEndian(fSectHeaders[i].Offset);
+      fSectHeaders[i].Size:=SwapEndian(fSectHeaders[i].Size);
+      fSectHeaders[i].Link:=SwapEndian(fSectHeaders[i].Link);
+      fSectHeaders[i].Info:=SwapEndian(fSectHeaders[i].Info);
+      fSectHeaders[i].AddrAlign:=SwapEndian(fSectHeaders[i].AddrAlign);
+      fSectHeaders[i].EntSize:=SwapEndian(fSectHeaders[i].EntSize);
+    end;
+  end;
+end;
+
+procedure _TElfSubReader_.ReadStringTable(aStream: TStream);
+begin
+  if ((fElfHdr.NameTableIndex<=0) or
+      (fElfHdr.NameTableIndex>=fElfHdr.SectHdrNum)) then
+    raise EElfResourceReaderNoStringTableException.Create('');
+  aStream.Position:=fSectHeaders[fElfHdr.NameTableIndex].Offset;
+  fStringTable:=TObjectStringTable.Create(aStream,fSectHeaders[fElfHdr.NameTableIndex].Size);
+end;
+
+function _TElfSubReader_.FindSection(const aName : string) : integer;
+var i : integer;
+    sectname : string;
+begin
+  for i:=1 to fElfHdr.SectHdrNum-1 do
+  begin
+    sectname:=fStringTable.Get(fSectHeaders[i].NameIdx);
+    if sectname=aName then
+    begin
+      Result:=i;
+      exit;
+    end;
+  end;
+  Result:=-1;
+end;
+
+procedure _TElfSubReader_.ReadRelocations(aStream : TStream);
+begin
+  fRelocations:=_TElfRelocTable_.Create(aStream,fSectHeaders[fRelSectIdx],fOppositeEndianess);
+end;
+
+procedure _TElfSubReader_.ReadResHeader(aStream: TStream);
+begin
+  aStream.Position:=fSectHeaders[fSectIdx].offset;
+  aStream.ReadBuffer(fResHdr,sizeof(fResHdr));
+  if fOppositeEndianess then
+  begin
+    fResHdr.rootptr:=SwapEndian(fResHdr.rootptr);
+    fResHdr.count:=SwapEndian(fResHdr.count);
+  end;
+  if fNeedsReloc then
+    fResHdr.rootptr:=fRelocations.Get(0);
+  aStream.Position:=fSectHeaders[fSectIdx].offset+fResHdr.rootptr-fSectHeaders[fSectIdx].address;
+end;
+
+procedure _TElfSubReader_.ReadNode(aStream : TStream; aParent : TResourceTreeNode;
+      aResources : TResources; named : boolean);
+var infonode : _TResInfoNode_;
+    aNode : TResourceTreeNode;
+    i : integer;
+    oldpos : int64;
+    baseofs : _Tword_;
+begin
+  baseofs:=aStream.Position-fSectHeaders[fSectIdx].offset;
+  aStream.ReadBuffer(infonode,sizeof(infonode));
+  oldpos:=aStream.Position;
+  if fOppositeEndianess then
+  begin
+    infonode.nameid:=SwapEndian(infonode.nameid);
+    infonode.ncount:=SwapEndian(infonode.ncount);
+    infonode.idcountsize:=SwapEndian(infonode.idcountsize);
+    infonode.subptr:=SwapEndian(infonode.subptr);
+  end;
+  if fNeedsReloc then
+  begin
+    if named then infonode.nameid:=fRelocations.Get(baseofs);
+    infonode.subptr:=fRelocations.Get(baseofs+(sizeof(_Tword_)+sizeof(longword)*2));
+  end;
+  if aParent=nil then aNode:=fRoot
+  else
+  begin
+    if named then dummyDesc.Name:=ReadString(aStream,
+      fSectHeaders[fSectIdx].offset+infonode.nameid-fSectHeaders[fSectIdx].address)
+    else dummyDesc.ID:=infonode.nameid;
+    aNode:=aParent.CreateSubNode(dummyDesc);
+  end;
+  aStream.Position:=fSectHeaders[fSectIdx].offset+infonode.subptr-fSectHeaders[fSectIdx].address;
+  if aNode.IsLeaf then
+    ReadResData(aStream,aNode,aResources,infonode.idcountsize)
+  else
+  begin
+    for i:=1 to infonode.ncount do
+      ReadNode(aStream,aNode,aResources,true);
+    for i:=1 to infonode.idcountsize do
+      ReadNode(aStream,aNode,aResources,false);
+  end;
+  aStream.Position:=oldpos;
+end;
+
+procedure _TElfSubReader_.Load(aResources: TResources; aStream: TStream);
+begin
+  ReadElfHeader(aStream);
+  ReadSectionHeaders(aStream);
+  ReadStringTable(aStream);
+  if not FindResSection then exit;
+  if fNeedsReloc then
+    ReadRelocations(aStream);
+  try
+    ReadResHeader(aStream);
+    if fResHdr.count=0 then exit; //no resources in this file
+    LoadResources(aResources,aStream);
+  finally
+    if fNeedsReloc then
+      fRelocations.Free;
+  end;
+end;
+

+ 446 - 0
packages/fcl-res/src/elfsubwriter.inc

@@ -0,0 +1,446 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource writer for ELF files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+type
+
+(*
+  generic TElfRelocTable<_TPElfRela_,_TElfRela_,_TPElfRel_,_TElfRel_,_Tword_> = class
+  ...
+  TElf32RelocTable = specialize TElfRelocTable<PElf32Rela,TElf32Rela,
+                                               PElf32Rel,TElf32Rel,longword>;
+  TElf64RelocTable = specialize TElfRelocTable<PElf64Rela,TElf64Rela,
+                                               PElf64Rel,TElf64Rel,qword>;
+*)
+
+  _TElfRelocTable_= class
+  private
+    fList : TFPList;
+    fRelocType : byte;
+    fEntrySize : integer;
+    fSectionType : integer;
+    fSectionName : string;
+    function GetCount : integer;
+    function GetItem(index : integer) : _TPElfRela_;
+  protected
+  public
+    constructor Create(const fRelocInfo : TElfRelocInfo);
+    destructor Destroy; override;
+    procedure Add(const aOffset,aValue : _Tword_; aSymIdx : longword);
+    procedure Clear;
+    property Count : integer read GetCount;
+    property Items[index : integer] : _TPElfRela_ read GetItem; default;
+    property EntrySize : integer read fEntrySize;
+    property SectionType : integer read fSectionType;
+    property SectionName : string read fSectionName;
+  end;
+  
+  { TElfSubWriter }
+
+(*
+  generic TElfSubWriter<_TElfRelocTable_,_TElfHdr_,_TElfSectHdr_,_TElfSymbol_,
+    _TPElfRela_,_TElfRela_,_TResHdr_,_TResInfoNode_> = class
+  ...
+  TElf32SubWriter = specialize TElfSubWriter<TElf32RelocTable,_TElf32Hdr_,
+    TElf32SectHdr,TElf32Symbol,PElf32Rela,TElf32Rela,TResHdr32,TResInfoNode32>;
+
+  TElf64SubWriter = specialize TElfSubWriter<TElf64RelocTable,_TElf64Hdr_,
+    TElf64SectHdr,TElf64Symbol,PElf64Rela,TElf64Rela,TResHdr64,TResInfoNode64>;
+*)
+
+  _TElfSubWriter_ = class(TAbstractElfSubWriter)
+  private
+    fRelocInfo :   TElfRelocInfo;
+    fRelocTable : _TElfRelocTable_;
+    procedure PrescanResourceTree; override;
+    procedure WriteEmptyElfHeader(aStream : TStream);
+    procedure WriteResHeader(aStream : TStream; aResources : TResources);
+    procedure WriteNodeInfos(aStream : TStream);
+    procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override;
+    procedure WriteSectHeaders(aStream : TStream);
+    procedure FixElfHeader(aStream : TStream);
+    procedure WriteSymbols(aStream : TStream);
+    procedure WriteRelocations(aStream : TStream);
+  protected
+    procedure Write(aResources : TResources; aStream : TStream); override;
+  public
+    constructor Create(aParent : TElfResourceWriter; const aMachineType
+      : integer; const aOppositeEndianess : boolean); override;
+    destructor Destroy; override;
+  end;
+
+{ TElfRelocTable }
+
+function _TElfRelocTable_.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+function _TElfRelocTable_.GetItem(index: integer): _TPElfRela_;
+begin
+  Result:=_TPElfRela_(fList[index]);
+end;
+
+constructor _TElfRelocTable_.Create(const fRelocInfo : TElfRelocInfo);
+begin
+  fList:=TFPList.Create;
+  fRelocType:=fRelocInfo.RelocType;
+  fSectionType:=fRelocInfo.SectionType;
+  case fSectionType of
+    SHT_REL  : begin
+                 fEntrySize:= sizeof(_TElfRel_);
+                 fSectionName:='.rel'+RsrcSectName;
+               end;
+    SHT_RELA : begin
+                 fEntrySize:= sizeof(_TElfRela_);
+                 fSectionName:='.rela'+RsrcSectName;
+               end;
+  end;
+end;
+
+destructor _TElfRelocTable_.Destroy;
+begin
+  Clear;
+  fList.Free;
+end;
+
+procedure _TElfRelocTable_.Add(const aOffset,aValue : _Tword_; aSymIdx : longword);
+var p : _TPElfRela_;
+begin
+  p:=GetMem(sizeof(_TElfRela_));
+  p^.Offset:=aOffset;
+  P^.Info:=aSymIdx;
+  {$IF _TElfRelocTable_=TElf64RelocTable}
+  P^.Info:=P^.Info shl 32;
+  P^.Info:=P^.Info or fRelocType;
+  {$ELSE}
+  P^.Info:=P^.Info shl 8;
+  P^.Info:=P^.Info or (fRelocType and $FF);
+  {$ENDIF}
+  p^.addend:=aValue;
+  fList.Add(p);
+end;
+
+procedure _TElfRelocTable_.Clear;
+var i : integer;
+    p : _TPElfRela_;
+begin
+  for i:=0 to fList.Count-1 do
+  begin
+    p:=_TPElfRela_(fList[i]);
+    FreeMem(p);
+  end;
+  fList.Clear;
+end;
+
+
+{ TElfSubWriter }
+
+procedure _TElfSubWriter_.PrescanResourceTree;
+begin
+  fResStringTable.Clear;
+  fRoot.SubDirRVA:=sizeof(_TResHdr_)+sizeof(_TResInfoNode_);
+  fResStringTable.StartOfs:=PrescanNode(fRoot,sizeof(_TResInfoNode_));
+  if fResStringTable.Used then
+    fDataCurOfs:=NextAligned(fDataAlignment,fResStringTable.StartOfs+fResStringTable.Size)
+  else
+    fDataCurOfs:=fResStringTable.StartOfs;
+end;
+
+procedure _TElfSubWriter_.WriteEmptyElfHeader(aStream: TStream);
+var hdr : _TElfHdr_;
+begin
+  FillByte(hdr,sizeof(hdr),0);
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+end;
+
+procedure _TElfSubWriter_.WriteResHeader(aStream: TStream;
+  aResources: TResources);
+var hdr : _TResHdr_;
+begin
+  hdr.count:=aResources.Count;
+  hdr.usedhandles:=0;
+  hdr.handles:=0;
+  
+  fSymbolTable.AddSection(RSRCSECT_IDX);
+  fSymbolTable.AddSection(HANDLESECT_IDX);
+  case fRelocInfo.SectionType of
+    SHT_REL  : hdr.rootptr:=sizeof(hdr);
+    SHT_RELA : hdr.rootptr:=0;
+  end;
+
+  fRelocTable.Add(0,sizeof(hdr),RSRCSECT_IDX);
+  fRelocTable.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),0,HANDLESECT_IDX);
+  if fOppositeEndianess then
+  begin
+    hdr.rootptr:=SwapEndian(hdr.rootptr);
+    hdr.count:=SwapEndian(hdr.count);
+    //handles must be fixed later
+//    hdr.usedhandles:=SwapEndian(hdr.usedhandles);
+//    hdr.handles:=SwapEndian(hdr.handles);
+  end;
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+end;
+
+procedure _TElfSubWriter_.WriteNodeInfos(aStream: TStream);
+begin
+  fCurOfs:=sizeof(_TResHdr_);
+  WriteNodeInfo(aStream,fRoot);
+  WriteSubNodes(aStream,fRoot);
+end;
+
+procedure _TElfSubWriter_.WriteNodeInfo(aStream: TStream;
+  aNode: TResourceTreeNode);
+var infonode : _TResInfoNode_;
+begin
+  if aNode.Desc.DescType=dtID then
+    infonode.nameid:=aNode.Desc.ID
+  else
+  begin
+    infonode.nameid:=fResStringTable.StartOfs+aNode.NameRVA;
+    fRelocTable.Add(fCurOfs,infonode.nameid,RSRCSECT_IDX);
+    if fRelocInfo.SectionType=SHT_RELA then infonode.nameid:=0;
+  end;
+  infonode.ncount:=aNode.NamedCount;
+  if aNode.IsLeaf then
+  begin
+    infonode.idcountsize:=aNode.Data.RawData.Size;
+    infonode.subptr:=fDataCurOfs;
+    fDataCurOfs:=NextAligned(fDataAlignment,fDataCurOfs+infonode.idcountsize);
+  end
+  else
+  begin
+    infonode.idcountsize:=aNode.IDCount;
+    infonode.subptr:=aNode.SubDirRVA;
+  end;
+  fRelocTable.Add(
+    fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+
+    sizeof(infonode.idcountsize),infonode.subptr,RSRCSECT_IDX);
+  if fRelocInfo.SectionType=SHT_RELA then infonode.subptr:=0;
+  if fOppositeEndianess then
+  begin
+    infonode.nameid:=SwapEndian(infonode.nameid);
+    infonode.ncount:=SwapEndian(infonode.ncount);
+    infonode.idcountsize:=SwapEndian(infonode.idcountsize);
+    infonode.subptr:=SwapEndian(infonode.subptr);
+  end;
+  aStream.WriteBuffer(infonode,sizeof(infonode));
+  inc(fCurOfs,sizeof(infonode));
+end;
+
+procedure _TElfSubWriter_.WriteSectHeaders(aStream: TStream);
+var i : integer;
+    orig : PElf64SectHdr;
+    hdr : _TElfSectHdr_;
+begin
+  Align(fDataAlignment,aStream);
+  fSectHdrOffset:=aStream.Position;
+  for i:=0 to fSections.Count-1 do
+  begin
+    orig:=fSections[i];
+    {$IF _TElfSubWriter_=TElf64SubWriter}
+    hdr:=orig^;
+    {$ELSE}
+    hdr.NameIdx:=orig^.NameIdx;
+    hdr._Type:=orig^._Type;
+    hdr.Flags:=orig^.Flags;
+    hdr.Address:=orig^.Address;
+    hdr.Offset:=orig^.Offset;
+    hdr.Size:=orig^.Size;
+    hdr.Link:=orig^.Link;
+    hdr.Info:=orig^.Info;
+    hdr.AddrAlign:=orig^.AddrAlign;
+    hdr.EntSize:=orig^.EntSize;
+    {$ENDIF}
+
+    if fOppositeEndianess then
+    begin
+      hdr.NameIdx:=SwapEndian(hdr.NameIdx);
+      hdr._Type:=SwapEndian(hdr._Type);
+      hdr.Flags:=SwapEndian(hdr.Flags);
+      hdr.Address:=SwapEndian(hdr.Address);
+      hdr.Offset:=SwapEndian(hdr.Offset);
+      hdr.Size:=SwapEndian(hdr.Size);
+      hdr.Link:=SwapEndian(hdr.Link);
+      hdr.Info:=SwapEndian(hdr.Info);
+      hdr.AddrAlign:=SwapEndian(hdr.AddrAlign);
+      hdr.EntSize:=SwapEndian(hdr.EntSize);
+    end;
+
+    aStream.WriteBuffer(hdr,sizeof(hdr));
+  end;
+end;
+
+procedure _TElfSubWriter_.FixElfHeader(aStream: TStream);
+var hdr : _TElfHdr_;
+begin
+  hdr._Type:=ET_REL;
+  hdr.Machine:=fMachineType;
+  hdr.Version:=EV_CURRENT;
+  hdr.Entry:=0;
+  hdr.ProgHdrOffset:=0;
+  hdr.SectHdrOffset:=fSectHdrOffset;
+  hdr.Flags:=fMachineFlags;
+  hdr.HdrSize:=sizeof(_TElfHdr_)+sizeof(TElfIdent);
+  hdr.ProgHdrEntrySize:=0;
+  hdr.ProgHdrNum:=0;
+  hdr.SectHdrEntrySize:=sizeof(_TElfSectHdr_);
+  hdr.SectHdrNum:=fSections.Count;
+  hdr.NameTableIndex:=fShStrTabIdx;
+
+  if fOppositeEndianess then
+  begin
+    hdr._Type:=SwapEndian(hdr._Type);
+    hdr.Machine:=SwapEndian(hdr.Machine);
+    hdr.Version:=SwapEndian(hdr.Version);
+    hdr.Entry:=SwapEndian(hdr.Entry);
+    hdr.ProgHdrOffset:=SwapEndian(hdr.ProgHdrOffset);
+    hdr.SectHdrOffset:=SwapEndian(hdr.SectHdrOffset);
+    hdr.Flags:=SwapEndian(hdr.Flags);
+    hdr.HdrSize:=SwapEndian(hdr.HdrSize);
+    hdr.ProgHdrEntrySize:=SwapEndian(hdr.ProgHdrEntrySize);
+    hdr.ProgHdrNum:=SwapEndian(hdr.ProgHdrNum);
+    hdr.SectHdrEntrySize:=SwapEndian(hdr.SectHdrEntrySize);
+    hdr.SectHdrNum:=SwapEndian(hdr.SectHdrNum);
+    hdr.NameTableIndex:=SwapEndian(hdr.NameTableIndex);
+  end;
+
+  aStream.Position:=sizeof(TElfIdent);
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+end;
+
+procedure _TElfSubWriter_.WriteSymbols(aStream: TStream);
+var i : integer;
+    orig : PElf64Symbol;
+    sym : _TElfSymbol_;
+    startpos : int64;
+begin
+  Align(fDataAlignment,aStream);
+  startpos:=aStream.Position;
+  for i:=0 to fSymbolTable.Count-1 do
+  begin
+    orig:=fSymbolTable[i];
+    {$IF _TElfSubWriter_=TElf64SubWriter}
+    sym:=orig^;
+    {$ELSE}
+    sym.Name:=orig^.Name;
+    sym.Value:=orig^.Value;
+    sym.Size:=orig^.Size;
+    sym.Info:=orig^.Info;
+    sym.Other:=orig^.Other;
+    sym.SectIdx:=orig^.SectIdx;
+    {$ENDIF}
+
+    if fOppositeEndianess then
+    begin
+      sym.Name:=SwapEndian(sym.Name);
+      sym.Value:=SwapEndian(sym.Value);
+      sym.Size:=SwapEndian(sym.Size);
+      sym.SectIdx:=SwapEndian(sym.SectIdx);
+    end;
+
+    aStream.WriteBuffer(sym,sizeof(sym));
+  end;
+
+  fSymTabIdx:=fSections.Add('.symtab',SHT_SYMTAB,0,startpos,
+    fSymbolTable.Count*sizeof(_TElfSymbol_),sizeof(_TElfSymbol_),fSymStrTabIdx,
+    fSymbolTable.FirstGlobal,fDataAlignment);
+end;
+
+procedure _TElfSubWriter_.WriteRelocations(aStream: TStream);
+var orig : _TPElfRela_;
+    rel : _TElfRela_;
+    startpos : int64;
+    i : integer;
+begin
+  Align(fDataAlignment,aStream);
+  startpos:=aStream.Position;
+  for i:=0 to fRelocTable.Count-1 do
+  begin
+    orig:=fRelocTable[i];
+    rel:=orig^;
+
+    if fOppositeEndianess then
+    begin
+      rel.Offset:=SwapEndian(rel.Offset);
+      rel.Info:=SwapEndian(rel.Info);
+      rel.Addend:=SwapEndian(rel.Addend);
+    end;
+
+    aStream.WriteBuffer(rel,fRelocTable.EntrySize);
+  end;
+
+  fSections.Add(fRelocTable.SectionName,fRelocTable.SectionType,0,startpos,
+    fRelocTable.Count*fRelocTable.EntrySize,fRelocTable.EntrySize,
+    fSymTabIdx,1,fDataAlignment);
+end;
+
+procedure _TElfSubWriter_.Write(aResources: TResources; aStream: TStream);
+begin
+  fRoot:=TRootResTreeNode(fParent.GetTree(aResources));
+  WriteEmptyElfHeader(aStream);
+  fSectionStart:=aStream.Position;
+  PrescanResourceTree;
+  WriteResHeader(aStream,aResources);
+  WriteNodeInfos(aStream);
+  WriteResStringTable(aStream);
+  WriteRawData(aStream);
+  fSections.Add(RsrcSectName, SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,fSectionStart,
+    fDataCurOfs,fDataAlignment);
+  AddEmptySections(aResources,aStream);
+  fSymbolTable.AddGlobal('FPC_RESSYMBOL',0,0,STT_OBJECT,RSRCSECT_IDX);
+  WriteStrTab(aStream);
+  WriteSymbols(aStream);
+  WriteRelocations(aStream);
+  WriteShStrTab(aStream);
+  WriteSectHeaders(aStream);
+  FixElfHeader(aStream);
+end;
+
+constructor _TElfSubWriter_.Create(aParent : TElfResourceWriter; const
+  aMachineType: integer; const aOppositeEndianess: boolean);
+begin
+  inherited Create(aParent, aMachineType, aOppositeEndianess);
+
+  with fRelocInfo do
+    case aMachineType of
+      EM_386    : begin RelocType:=R_386_32;        SectionType:=SHT_REL;  end;
+      EM_PPC    : begin RelocType:=R_PPC_ADDR32;    SectionType:=SHT_RELA; end;
+      EM_ARM    : begin RelocType:=R_ARM_ABS32;     SectionType:=SHT_REL;  end;
+      EM_68K    : begin RelocType:=R_68K_32;        SectionType:=SHT_RELA; end;
+      EM_SPARC  : begin RelocType:=R_SPARC_32;      SectionType:=SHT_RELA; end;
+      EM_X86_64 : begin RelocType:=R_x86_64_64;     SectionType:=SHT_RELA; end;
+      EM_PPC64  : begin RelocType:=R_PPC64_ADDR64;  SectionType:=SHT_RELA; end;
+      EM_ALPHA  : begin RelocType:=R_ALPHA_REFQUAD; SectionType:=SHT_RELA; end;
+      EM_IA_64  : begin RelocType:=R_IA64_DIR64LSB; SectionType:=SHT_RELA; end;
+      else
+        raise EElfResourceWriterUnknownMachineException.Create('');
+    end;
+
+  fRelocTable:=_TElfRelocTable_.Create(fRelocInfo);
+  {$IF _TElfSubWriter_=TElf64SubWriter}
+  fDataAlignment:=8;
+  {$ELSE}
+  fDataAlignment:=4;
+  {$ENDIF}
+  if aMachineType=EM_IA_64 then fMachineFlags:=EF_IA_64_ABI64
+  else fMachineFlags:=0;
+end;
+
+destructor _TElfSubWriter_.Destroy;
+begin
+  fRelocTable.Free;
+  inherited Destroy;
+end;
+

+ 142 - 0
packages/fcl-res/src/elftypes.pp

@@ -0,0 +1,142 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Types used by ELF resource reader and writer
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit elftypes;
+
+{$MODE OBJFPC}
+
+interface
+
+type
+  TElfMagic = array[0..3] of char;
+
+type
+  TElfIdent = packed record
+    Magic : TElfMagic;              // 0..3
+    ElfClass : byte;                // 4
+    ElfData : byte;                 // 5
+    ElfVersion : byte;              // 6
+    OsAbi : byte;                   // 7
+    AbiVersion : byte;              // 8
+    Padding : array[9..15] of byte; // 9..15
+  end;
+
+  //note: it doesn't include Ident block
+  TElf32Hdr = packed record
+    _Type : word;
+    Machine : word;
+    Version : longword;
+    Entry : longword;
+    ProgHdrOffset : longword;
+    SectHdrOffset : longword;
+    Flags : longword;
+    HdrSize : word;
+    ProgHdrEntrySize : word;
+    ProgHdrNum : word;
+    SectHdrEntrySize : word;
+    SectHdrNum : word;
+    NameTableIndex : word;
+  end;
+
+  //note: it doesn't include Ident block
+  TElf64Hdr = packed record
+    _Type : word;
+    Machine : word;
+    Version : longword;
+    Entry : qword;
+    ProgHdrOffset : qword;
+    SectHdrOffset : qword;
+    Flags : longword;
+    HdrSize : word;
+    ProgHdrEntrySize : word;
+    ProgHdrNum : word;
+    SectHdrEntrySize : word;
+    SectHdrNum : word;
+    NameTableIndex : word;
+  end;
+
+  TElf32SectHdr = packed record
+    NameIdx : longword;
+    _Type : longword;
+    Flags : longword;
+    Address : longword;
+    Offset : longword;
+    Size : longword;
+    Link : longword;
+    Info : longword;
+    AddrAlign : longword;
+    EntSize : longword;
+  end;
+
+  TElf64SectHdr = packed record
+    NameIdx : longword;
+    _Type : longword;
+    Flags : qword;
+    Address : qword;
+    Offset : qword;
+    Size : qword;
+    Link : longword;
+    Info : longword;
+    AddrAlign : qword;
+    EntSize : qword;
+  end;
+  PElf64SectHdr = ^TElf64SectHdr;
+  
+  TElf32Symbol = packed record
+    Name : longword;
+    Value : longword;
+    Size : longword;
+    Info : byte;
+    Other : byte;
+    SectIdx : word;
+  end;
+  
+  TElf64Symbol = packed record
+    Name : longword;
+    Info : byte;
+    Other : byte;
+    SectIdx : word;
+    Value : qword;
+    Size : qword;
+  end;
+  PElf64Symbol = ^TElf64Symbol;
+
+  TElf32Rel = packed record
+    Offset : longword;
+    Info   : longword;
+  end;
+
+  TElf32Rela = packed record
+    Offset : longword;
+    Info   : longword;
+    addend : longint;
+  end;
+  PElf32Rela = ^TElf32Rela;
+
+  TElf64Rel = packed record
+    Offset : qword;
+    Info   : qword;
+  end;
+
+  TElf64Rela = packed record
+    Offset : qword;
+    Info   : qword;
+    addend : int64;
+  end;
+  PElf64Rela = ^TElf64Rela;
+
+implementation
+
+end.

+ 620 - 0
packages/fcl-res/src/elfwriter.pp

@@ -0,0 +1,620 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource writer for ELF files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit elfwriter;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, elfconsts, elftypes;
+
+type
+  EElfResourceWriterException = class(EResourceWriterException);
+  EElfResourceWriterUnknownMachineException = class(EElfResourceWriterException);
+  EElfResourceWriterUnknownClassException = class(EElfResourceWriterException);
+  EElfResourceWriterUnknownSectionException = class(EElfResourceWriterException);
+
+type
+  { TElfResourceWriter }
+
+  TElfResourceWriter = class (TAbstractResourceWriter)
+  private
+    fExtensions : string;
+    fDescription : string;
+    fMachineTypeInt : integer;
+    fMachineType : TElfMachineType;
+    fOrder : byte;
+    fBits : byte;
+    fNativeOrder : integer;
+    fOppositeEndianess : boolean;
+    procedure SetDefaultTarget;
+    procedure SetMachineType(const aMachineType : TElfMachineType);
+    
+    procedure WriteElfIdent(aStream : TStream);
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Write(aResources : TResources; aStream : TStream); override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    property MachineType : TElfMachineType read fMachineType write SetMachineType;
+  end;
+
+
+implementation
+
+uses resourcetree, strtable, fpcrestypes;
+
+type
+
+  { TElfSections }
+
+  TElfSections = class
+  private
+    fList : TFPList;
+    fStringTable : TObjectStringTable;
+    function GetCount : integer;
+    function GetItem(index : integer) : PElf64SectHdr;
+  protected
+  public
+    constructor Create(aStringTable : TObjectStringTable);
+    destructor Destroy; override;
+    function Add(const aName: string; const aType, aFlags : longword;
+      const aOffset, aSize : qword; const aAddrAlign : longword) : integer; overload;
+    function Add(const aName: string; const aType, aFlags : longword;
+      const aOffset, aSize, aEntSize : qword; const aLink, aInfo,aAddrAlign
+      : longword) : integer; overload;
+    procedure Clear;
+    property Count : integer read GetCount;
+    property Items[index : integer] : PElf64SectHdr read GetItem; default;
+  end;
+
+  { TElfSymbolTable }
+
+  TElfSymbolTable = class
+  private
+    fList : TFPList;
+    fSectFree : integer;
+    fLocFree : integer;
+    fStringTable : TObjectStringTable;
+    function CreateSym(const aName : string; const aValue, aSize : qword;
+      const aBind, aType : byte; const aSectIdx : integer) : PElf64Symbol;
+    procedure Clear;
+    function GetCount : integer;
+    function GetItem(index : integer) : PElf64Symbol;
+  protected
+  public
+    constructor Create(aStringTable : TObjectStringTable);
+    destructor Destroy; override;
+    procedure AddSection(const aSectIdx : integer);
+    procedure AddLocal(const aName : string; const aValue, aSize : qword;
+      const aType : byte; const aSectIdx : integer);
+    procedure AddGlobal(const aName : string; const aValue, aSize : qword;
+      const aType : byte; const aSectIdx : integer);
+    property Count : integer read GetCount;
+    property Items[index : integer] : PElf64Symbol read GetItem; default;
+    property FirstGlobal : integer read fLocFree;
+  end;
+  
+  { TAbstractElfSubWriter }
+
+  TAbstractElfSubWriter = class
+  private
+  protected
+    fParent : TElfResourceWriter;
+    fOppositeEndianess : boolean;
+    fMachineType : integer;
+    fDataAlignment : longword;
+    fMachineFlags : longword;
+    fRoot : TRootResTreeNode;
+    fSectStringTable : TObjectStringTable;
+    fSymStringTable  : TObjectStringTable;
+    fResStringTable : TResStringTable;
+    fSymbolTable : TElfSymbolTable;
+    fSections : TElfSections;
+    fShStrTabIdx : integer;
+    fSymStrTabIdx : integer;
+    fSymTabIdx : integer;
+    fSectHdrOffset : qword;
+    fCurOfs : longword;
+    fDataCurOfs : longword;
+    fSectionStart : qword;
+    procedure Align(aBound : integer; aStream : TStream);
+    function NextAligned(aBound, aValue : longword) : longword;
+    procedure PrescanResourceTree; virtual; abstract;
+    function PrescanNode(aNode : TResourceTreeNode; aNodeSize : longword) : longword;
+    procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); virtual; abstract;
+    procedure WriteSubNodes(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteResStringTable(aStream : TStream);
+    procedure WriteRawData(aStream : TStream);
+    procedure WriteResData(aStream : TStream; aNode : TResourceTreeNode);
+    procedure AddEmptySections(aResources : TResources; aStream : TStream);
+    procedure WriteStrTab(aStream : TStream);
+    procedure WriteShStrTab(aStream : TStream);
+    procedure Write(aResources : TResources; aStream : TStream); virtual; abstract;
+  public
+    constructor Create(aParent : TElfResourceWriter; const aMachineType : integer;
+      const aOppositeEndianess : boolean); virtual;
+    destructor Destroy; override;
+  end;
+
+type
+  TElfRelocInfo = record
+    RelocType : byte;
+    SectionType : integer;
+  end;
+(*
+Almost all differences in 32 and 64 bit elf files lie in record sizes.
+Generics don't work with record types, so use macros to do this task
+(uglier, but should be the same)
+*)
+
+{$MACRO ON}
+
+//Define TElf32RelocTable and TElf32SubWriter
+
+{$DEFINE _TElfRelocTable_:=TElf32RelocTable}
+{$DEFINE _TPElfRela_:=PElf32Rela}
+{$DEFINE _TElfRela_:=TElf32Rela}
+{$DEFINE _TPElfRel_:=PElf32Rel}
+{$DEFINE _TElfRel_:=TElf32Rel}
+{$DEFINE _Tword_:=longword}
+{$DEFINE _TElfSubWriter_:=TElf32SubWriter}
+{$DEFINE _TElfHdr_:=TElf32Hdr}
+{$DEFINE _TElfSectHdr_:=TElf32SectHdr}
+{$DEFINE _TElfSymbol_:=TElf32Symbol}
+{$DEFINE _TResHdr_:=TResHdr32}
+{$DEFINE _TResInfoNode_:=TResInfoNode32}
+{$INCLUDE elfsubwriter.inc}
+
+
+//Define TElf64RelocTable and TElf32SubWriter
+
+{$DEFINE _TElfRelocTable_:=TElf64RelocTable}
+{$DEFINE _TPElfRela_:=PElf64Rela}
+{$DEFINE _TElfRela_:=TElf64Rela}
+{$DEFINE _TPElfRel_:=PElf64Rel}
+{$DEFINE _TElfRel_:=TElf64Rel}
+{$DEFINE _Tword_:=qword}
+{$DEFINE _TElfSubWriter_:=TElf64SubWriter}
+{$DEFINE _TElfHdr_:=TElf64Hdr}
+{$DEFINE _TElfSectHdr_:=TElf64SectHdr}
+{$DEFINE _TElfSymbol_:=TElf64Symbol}
+{$DEFINE _TResHdr_:=TResHdr64}
+{$DEFINE _TResInfoNode_:=TResInfoNode64}
+{$INCLUDE elfsubwriter.inc}
+
+
+//Clean all this stuff...
+
+{$UNDEF _TElfRelocTable_}
+{$UNDEF _TPElfRela_}
+{$UNDEF _TElfRela_}
+{$UNDEF _TPElfRel_}
+{$UNDEF _TElfRel_}
+{$UNDEF _Tword_}
+{$UNDEF _TElfSubWriter_}
+{$UNDEF _TElfHdr_}
+{$UNDEF _TElfSectHdr_}
+{$UNDEF _TElfSymbol_}
+{$UNDEF _TResHdr_}
+{$UNDEF _TResInfoNode_}
+
+
+{ TElfSections }
+
+function TElfSections.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+function TElfSections.GetItem(index: integer): PElf64SectHdr;
+begin
+  Result:=PElf64SectHdr(fList[index]);
+end;
+
+constructor TElfSections.Create(aStringTable : TObjectStringTable);
+begin
+  fList:=TFPList.Create;
+  fStringTable:=aStringTable;
+  Add('',0,0,0,0,0); //empty section
+end;
+
+destructor TElfSections.Destroy;
+var i : integer;
+    p : PElf64SectHdr;
+begin
+  for i:=0 to fList.Count-1 do
+  begin
+    p:=PElf64SectHdr(fList[i]);
+    FreeMem(p);
+  end;
+
+  fList.Free;
+end;
+
+function TElfSections.Add(const aName: string; const aType, aFlags : longword;
+  const aOffset, aSize : qword; const aAddrAlign : longword) : integer;
+begin
+  Result:=Add(aName,aType,aFlags,aOffset,aSize,0,0,0,aAddrAlign);
+end;
+
+function TElfSections.Add(const aName: string; const aType, aFlags: longword;
+  const aOffset, aSize, aEntSize: qword; const aLink, aInfo, aAddrAlign: longword): integer;
+var p : PElf64SectHdr;
+begin
+  Result:=fList.Count;
+  p:=GetMem(sizeof(TElf64SectHdr));
+  p^.NameIdx:=fStringTable.Add(aName);
+  p^._Type:=aType;
+  p^.Flags:=aFlags;
+  p^.Address:=0;
+  p^.Offset:=aOffset;;
+  p^.Size:=aSize;
+  p^.Link:=aLink;
+  p^.Info:=aInfo;
+  p^.AddrAlign:=aAddrAlign;
+  p^.EntSize:=aEntSize;
+  fList.Add(p);
+end;
+
+procedure TElfSections.Clear;
+var i : integer;
+    p, first : PElf64SectHdr;
+begin
+  first:=PElf64SectHdr(fList[0]);
+  for i:=1 to fList.Count-1 do
+  begin
+    p:=PElf64SectHdr(fList[i]);
+    FreeMem(p);
+  end;
+  fList.Clear;
+  fList.Add(first);
+end;
+
+{ TElfSymbolTable }
+
+constructor TElfSymbolTable.Create(aStringTable: TObjectStringTable);
+var p : PElf64Symbol;
+begin
+  fList:=TFPList.Create;
+  fStringTable:=aStringTable;
+  p:=CreateSym('',0,0,0,0,0);
+  fList.Add(p);
+  fSectFree:=1;
+  fLocFree:=1;
+end;
+
+destructor TElfSymbolTable.Destroy;
+begin
+  Clear;
+  fList.Free;
+end;
+
+procedure TElfSymbolTable.AddSection(const aSectIdx: integer);
+var p : PElf64Symbol;
+begin
+  p:=CreateSym('',0,0,STB_LOCAL,STT_SECTION,aSectIdx);
+  if fSectFree=fList.Count then
+    fList.Add(p)
+  else
+    fList.Insert(fSectFree,p);
+  inc(fSectFree);
+  inc(fLocFree);
+end;
+
+procedure TElfSymbolTable.AddLocal(const aName: string; const aValue,
+  aSize: qword; const aType: byte; const aSectIdx: integer);
+var p : PElf64Symbol;
+begin
+  p:=CreateSym(aName,aValue,aSize,STB_LOCAL,aType,aSectIdx);
+  if fLocFree=fList.Count then
+    fList.Add(p)
+  else
+    fList.Insert(fLocFree,p);
+  inc(fLocFree);
+end;
+
+procedure TElfSymbolTable.AddGlobal(const aName: string; const aValue,
+  aSize: qword; const aType: byte; const aSectIdx: integer);
+var p : PElf64Symbol;
+begin
+  p:=CreateSym(aName,aValue,aSize,STB_GLOBAL,aType,aSectIdx);
+  fList.Add(p)
+end;
+
+procedure TElfSymbolTable.Clear;
+var p : PElf64Symbol;
+    i : integer;
+begin
+  for i:=0 to fList.Count-1 do
+  begin
+    p:=PElf64Symbol(fList[i]);
+    FreeMem(p);
+  end;
+  fList.Clear;
+end;
+
+function TElfSymbolTable.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+function TElfSymbolTable.GetItem(index: integer): PElf64Symbol;
+begin
+  Result:=PElf64Symbol(fList[index]);
+end;
+
+function TElfSymbolTable.CreateSym(const aName : string; const aValue, aSize : qword;
+      const aBind, aType : byte; const aSectIdx : integer) : PElf64Symbol;
+var p : PElf64Symbol;
+begin
+  p:=GetMem(sizeof(TElf64Symbol));
+  p^.Name:=fStringTable.Add(aName);
+  p^.Value:=aValue;
+  p^.Size:=aSize;
+  p^.Info:=aBind shl 4;
+  p^.Info:=p^.Info or (aType and $0F);
+  p^.Other:=0;
+  p^.SectIdx:=aSectIdx;
+  Result:=p;
+end;
+
+{ TAbstractElfSubWriter }
+
+procedure TAbstractElfSubWriter.Align(aBound : integer; aStream : TStream);
+var topad,tmp : integer;
+    qw : qword;
+begin
+  qw:=0;
+  topad:=aBound-(aStream.Position mod aBound);
+  if topad<>aBound then
+    while topad>0 do
+    begin
+      if topad>8 then tmp:=8 else tmp:=topad;
+      aStream.WriteBuffer(qw,tmp);
+      dec(topad,tmp);
+    end;
+end;
+
+function TAbstractElfSubWriter.NextAligned(aBound, aValue : longword) : longword;
+var topad : longword;
+begin
+  Result:=aValue;
+  topad:=aBound-(aValue mod aBound);
+  if topad<>aBound then inc(Result,topad);
+end;
+
+function TAbstractElfSubWriter.PrescanNode(aNode: TResourceTreeNode;
+  aNodeSize: longword): longword;
+var curofs : longword;
+    i : integer;
+    subnode : TResourceTreeNode;
+begin
+  if aNode.IsLeaf then
+  begin
+    Result:=aNode.SubDirRVA;
+    exit;
+  end;
+
+  if aNode.Desc.DescType=dtName then
+    aNode.NameRVA:=fResStringTable.Add(aNode.Desc.Name);
+
+  //first node subnodes begin at curofs (after all node headers)
+  curofs:=aNode.SubDirRva+(aNode.NamedCount+aNode.IDCount)*aNodeSize;
+  for i:=0 to aNode.NamedCount-1 do
+  begin
+    subnode:=aNode.NamedEntries[i];
+    subnode.SubDirRVA:=curofs;
+    curofs:=PrescanNode(subnode,aNodeSize);
+  end;
+  for i:=0 to aNode.IDCount-1 do
+  begin
+    subnode:=aNode.IDEntries[i];
+    subnode.SubDirRVA:=curofs;
+    curofs:=PrescanNode(subnode,aNodeSize);
+  end;
+  Result:=curofs;
+end;
+
+procedure TAbstractElfSubWriter.WriteSubNodes(aStream: TStream;
+  aNode: TResourceTreeNode);
+var i : integer;
+begin
+  for i:=0 to aNode.NamedCount-1 do
+    WriteNodeInfo(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteNodeInfo(aStream,aNode.IDEntries[i]);
+
+  for i:=0 to aNode.NamedCount-1 do
+    WriteSubNodes(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteSubNodes(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TAbstractElfSubWriter.WriteResStringTable(aStream: TStream);
+begin
+  if fResStringTable.Used then
+    fResStringTable.WriteToStream(aStream);
+  Align(fDataAlignment,aStream);
+end;
+
+
+procedure TAbstractElfSubWriter.WriteRawData(aStream: TStream);
+begin
+  WriteResData(aStream,fRoot);
+end;
+
+procedure TAbstractElfSubWriter.WriteResData(aStream: TStream;
+  aNode: TResourceTreeNode);
+var rawdata : TStream;
+    i : integer;
+begin
+  if aNode.IsLeaf then
+  begin
+    rawdata:=aNode.Data.RawData;
+    rawdata.Position:=0;
+    aStream.CopyFrom(rawdata,rawdata.Size);
+    Align(fDataAlignment,aStream);
+    exit;
+  end;
+  for i:=0 to aNode.NamedCount-1 do
+    WriteResData(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteResData(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TAbstractElfSubWriter.AddEmptySections(aResources : TResources; aStream: TStream);
+begin
+  Align(fDataAlignment,aStream);
+  fSections.Add(HandlesSectName,SHT_NOBITS,SHF_ALLOC or SHF_WRITE,
+    aStream.Position,fDataAlignment*aResources.Count,fDataAlignment);
+  fSections.Add('.text',SHT_PROGBITS,SHF_ALLOC or SHF_EXECINSTR,aStream.Position,0,4);
+  fSections.Add('.data',SHT_PROGBITS,SHF_ALLOC or SHF_WRITE,aStream.Position,0,4);
+  fSections.Add('.bss', SHT_NOBITS,SHF_ALLOC or SHF_WRITE,aStream.Position,0,4);
+end;
+
+procedure TAbstractElfSubWriter.WriteStrTab(aStream: TStream);
+begin
+  fSymStrTabIdx:=fSections.Add('.strtab',SHT_STRTAB,0,aStream.Position,
+    fSymStringTable.Size,1);
+  fSymStringTable.WriteToStream(aStream);
+end;
+
+procedure TAbstractElfSubWriter.WriteShStrTab(aStream: TStream);
+const namelen = length('.shstrtab')+1;
+begin
+  fShStrTabIdx:=fSections.Add('.shstrtab',SHT_STRTAB,0,aStream.Position,
+    fSectStringTable.Size+namelen,1);
+  fSectStringTable.WriteToStream(aStream);
+end;
+
+constructor TAbstractElfSubWriter.Create(aParent : TElfResourceWriter;
+  const aMachineType: integer; const aOppositeEndianess: boolean);
+begin
+  fMachineType:=aMachineType;
+  fOppositeEndianess:=aOppositeEndianess;
+  fRoot:=nil;
+  fParent:=aParent;
+  fSectStringTable:=TObjectStringTable.Create(nil,0);
+  fSymStringTable:=TObjectStringTable.Create(nil,0);
+  fResStringTable:=TResStringTable.Create;
+  fSymbolTable:=TElfSymbolTable.Create(fSymStringTable);
+  fSections:=TElfSections.Create(fSectStringTable);
+  fShStrTabIdx:=0;
+  fSymStrTabIdx:=0;
+  fSectHdrOffset:=0;
+  fCurOfs:=0;
+  fDataCurOfs:=0;
+  fSectionStart:=0;
+end;
+
+destructor TAbstractElfSubWriter.Destroy;
+begin
+  fSectStringTable.Free;
+  fSymStringTable.Free;
+  fResStringTable.Free;
+  fSymbolTable.Free;
+  fSections.Free;
+end;
+
+{ TElfResourceWriter }
+
+procedure TElfResourceWriter.SetDefaultTarget;
+begin
+  {$INCLUDE elfdefaulttarget.inc}
+end;
+
+procedure TElfResourceWriter.SetMachineType(const aMachineType: TElfMachineType);
+begin
+  case aMachineType of
+    emtsparc  : begin fMachineTypeInt:=EM_SPARC; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end;
+    emti386   : begin fMachineTypeInt:=EM_386; fBits:=ELFCLASS32; fOrder:=ELFDATA2LSB; end;
+    emtm68k   : begin fMachineTypeInt:=EM_68K; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end;
+    emtppc    : begin fMachineTypeInt:=EM_PPC; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end;
+    emtppc64  : begin fMachineTypeInt:=EM_PPC64; fBits:=ELFCLASS64; fOrder:=ELFDATA2MSB; end;
+    emtarm    : begin fMachineTypeInt:=EM_ARM; fBits:=ELFCLASS32; fOrder:=ELFDATA2LSB; end;
+    emtarmeb  : begin fMachineTypeInt:=EM_ARM; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end;
+    emtalpha  : begin fMachineTypeInt:=EM_ALPHA; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end;
+    emtia64   : begin fMachineTypeInt:=EM_IA_64; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end;
+    emtx86_64 : begin fMachineTypeInt:=EM_X86_64; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end
+    else
+      raise EElfResourceWriterUnknownMachineException.Create('');
+  end;
+  fMachineType:=aMachineType;
+  fOppositeEndianess:=fNativeOrder<>fOrder;
+end;
+
+procedure TElfResourceWriter.WriteElfIdent(aStream: TStream);
+var ident : TElfIdent;
+begin
+  ident.Magic:=ELFMAGIC;
+  ident.ElfClass:=fBits;
+  ident.ElfData:=fOrder;
+  ident.ElfVersion:=EV_CURRENT;
+  ident.OsAbi:=ELFOSABI_NONE; // UNIX System V ABI
+  ident.AbiVersion:=0;
+  FillByte(ident.Padding[9],length(ident.Padding),0);
+  
+  aStream.WriteBuffer(ident,sizeof(ident));
+end;
+
+function TElfResourceWriter.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TElfResourceWriter.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TElfResourceWriter.Write(aResources: TResources; aStream: TStream);
+var subwriter : TAbstractElfSubWriter;
+begin
+  WriteElfIdent(aStream);
+  case fBits of
+    ELFCLASS32 : subwriter:=TElf32SubWriter.Create(self,fMachineTypeInt,fOppositeEndianess);
+    ELFCLASS64 : subwriter:=TElf64SubWriter.Create(self,fMachineTypeInt,fOppositeEndianess)
+  else
+    raise EElfResourceWriterUnknownClassException.Create('');
+  end;
+  try
+    subwriter.Write(aResources,aStream);
+  finally
+    subwriter.Free;
+  end;
+end;
+
+constructor TElfResourceWriter.Create;
+begin
+  fExtensions:='.o .or';
+  fDescription:='ELF resource writer';
+  SetDefaultTarget;
+end;
+
+destructor TElfResourceWriter.Destroy;
+begin
+
+end;
+
+initialization
+  TResources.RegisterWriter('.o',TElfResourceWriter);
+  TResources.RegisterWriter('.or',TElfResourceWriter);
+
+end.

+ 231 - 0
packages/fcl-res/src/externalreader.pp

@@ -0,0 +1,231 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for external resource files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit externalreader;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, resourcetree, externaltypes;
+  
+type
+
+  { TExternalResourceReader }
+
+  TExternalResourceReader = class(TAbstractResourceReader)
+  private
+    fExtensions : string;
+    fDescription : string;
+    fNativeEndianess : byte;
+    fEndianess : byte;
+    fOppositeEndianess : boolean;
+    fFileHeader : TExtHeader;
+    fRoot : TRootResTreeNode;
+
+    function ReadString(aStream : TStream; aOfs : longword) : string;
+    function ReadFileHeader(aStream : TStream) : boolean;
+    procedure ReadResourceTree(aStream : TStream; aResources : TResources);
+    procedure ReadNode(aStream : TStream; aParent : TResourceTreeNode;
+      aResources : TResources; named : boolean);
+    procedure ReadResData(aStream : TStream; aNode : TResourceTreeNode;
+      aResources : TResources; datasize : longword);
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Load(aResources : TResources; aStream : TStream); override;
+    function CheckMagic(aStream : TStream) : boolean; override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    property Endianess : byte read fEndianess;
+  end;
+
+implementation
+
+uses
+  resdatastream, resfactory;
+
+{ TExternalResourceReader }
+
+function TExternalResourceReader.ReadString(aStream: TStream; aOfs: longword
+  ): string;
+var oldpos : int64;
+    c : char;
+    maxleft : int64;
+begin
+  Result:='';
+  oldpos:=aStream.Position;
+  aStream.Position:=aOfs;
+  
+  aStream.ReadBuffer(c,1);
+  maxleft:=aStream.Size-aStream.Position;
+  while (c<>#0) and (maxleft>=0) do
+  begin
+    Result:=Result+c;
+    aStream.ReadBuffer(c,1);
+    dec(maxleft);
+  end;
+  aStream.Position:=oldpos;
+end;
+
+function TExternalResourceReader.ReadFileHeader(aStream: TStream): boolean;
+var hdr : TExtHeader;
+begin
+  Result:=false;
+
+  try
+    aStream.ReadBuffer(hdr,sizeof(hdr));
+  except
+    on e : EReadError do exit;
+  end;
+  
+  if hdr.magic<>EXTERNAL_RESMAGIC then exit;
+  if hdr.version<>EXT_CURRENT_VERSION then exit;
+  if hdr.endianess<>fNativeEndianess then
+  begin
+    fEndianess:=hdr.endianess;
+    fOppositeEndianess:=true;
+  end;
+  if fOppositeEndianess then
+  begin
+    hdr.count:=SwapEndian(hdr.count);
+    hdr.nodesize:=SwapEndian(hdr.nodesize);
+    hdr.hdrsize:=SwapEndian(hdr.hdrsize);
+  end;
+  fFileHeader:=hdr;
+  Result:=true;
+end;
+
+procedure TExternalResourceReader.ReadResourceTree(aStream: TStream;
+  aResources: TResources);
+begin
+  aStream.Position:=sizeof(TExtHeader);
+  fRoot:=TRootResTreeNode(GetTree(aResources));
+  ReadNode(aStream,nil,aResources,false);
+end;
+
+procedure TExternalResourceReader.ReadNode(aStream: TStream;
+  aParent: TResourceTreeNode; aResources: TResources; named: boolean);
+var infonode : TResInfoNode;
+    aNode : TResourceTreeNode;
+    i : integer;
+    oldpos : int64;
+    desc : TResourceDesc;
+begin
+  aStream.ReadBuffer(infonode,sizeof(infonode));
+  oldpos:=aStream.Position;
+  if fOppositeEndianess then
+  begin
+    infonode.nameid:=SwapEndian(infonode.nameid);
+    infonode.ncount:=SwapEndian(infonode.ncount);
+    infonode.idcountsize:=SwapEndian(infonode.idcountsize);
+    infonode.subptr:=SwapEndian(infonode.subptr);
+  end;
+  if aParent=nil then aNode:=fRoot
+  else
+  begin
+    desc:=TResourceDesc.Create;
+    try
+      if named then desc.Name:=ReadString(aStream,infonode.nameid)
+      else desc.ID:=infonode.nameid;
+      aNode:=aParent.CreateSubNode(desc);
+    finally
+      desc.Free;
+    end;
+  end;
+  aStream.Position:=infonode.subptr;
+  if aNode.IsLeaf then
+    ReadResData(aStream,aNode,aResources,infonode.idcountsize)
+  else
+  begin
+    for i:=1 to infonode.ncount do
+      ReadNode(aStream,aNode,aResources,true);
+    for i:=1 to infonode.idcountsize do
+      ReadNode(aStream,aNode,aResources,false);
+  end;
+  aStream.Position:=oldpos;
+end;
+
+procedure TExternalResourceReader.ReadResData(aStream: TStream;
+  aNode: TResourceTreeNode; aResources: TResources; datasize: longword);
+var aRes : TAbstractResource;
+    RawData : TResourceDataStream;
+begin
+  aRes:=aNode.CreateResource;
+  if aRes=nil then
+    raise EResourceDuplicateException.CreateFmt(SResDuplicate,[
+      aNode.Data._Type.Name,aNode.Data.Name.Name,aNode.Data.LangID]);
+  SetDataSize(aRes,datasize);
+  SetDataOffset(aRes,aStream.Position);
+  RawData:=TResourceDataStream.Create(aStream,aRes,aRes.DataSize,TCachedResourceDataStream);
+  SetRawData(aRes,RawData);
+  AddNoTree(aResources,aRes);
+end;
+
+function TExternalResourceReader.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TExternalResourceReader.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TExternalResourceReader.Load(aResources: TResources; aStream: TStream
+  );
+begin
+  if not ReadFileHeader(aStream) then
+    raise EResourceReaderWrongFormatException.Create('');
+  try
+    if fFileHeader.count=0 then exit; //no resources in this file.
+    ReadResourceTree(aStream,aResources);
+  except
+    on e : EReadError do
+      raise EResourceReaderUnexpectedEndOfStreamException.Create('');
+  end;
+end;
+
+function TExternalResourceReader.CheckMagic(aStream: TStream): boolean;
+begin
+  Result:=ReadFileHeader(aStream);
+end;
+
+constructor TExternalResourceReader.Create;
+begin
+  fExtensions:='.fpcres .frs';
+  fDescription:='External file resource reader';
+  {$IFDEF ENDIAN_BIG}
+  fNativeEndianess:=EXT_ENDIAN_BIG;
+  {$ELSE}
+  fNativeEndianess:=EXT_ENDIAN_LITTLE;
+  {$ENDIF}
+  fEndianess:=fNativeEndianess;
+  fOppositeEndianess:=false;
+  fRoot:=nil;
+end;
+
+destructor TExternalResourceReader.Destroy;
+begin
+
+end;
+
+initialization
+  TResources.RegisterReader('.fpcres',TExternalResourceReader);
+  TResources.RegisterReader('.frs',TExternalResourceReader);
+
+end.

+ 56 - 0
packages/fcl-res/src/externaltypes.pp

@@ -0,0 +1,56 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Types and constants used by external resource reader and writer
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit externaltypes;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+type
+  TExternalResMagic = array[1..6] of char;
+
+type
+  TExtHeader = packed record
+    magic : TExternalResMagic;  //'FPCRES'
+    version : byte;             //EXT_CURRENT_VERSION
+    endianess : byte;           //EXT_ENDIAN_BIG or EXT_ENDIAN_LITTLE
+    count : longword;           //resource count
+    nodesize : longword;        //size of header (up to string table, excluded)
+    hdrsize  : longword;        //size of header (up to string table, included)
+    reserved1 : longword;
+    reserved2 : longword;
+    reserved3 : longword;
+  end;
+
+  TResInfoNode = packed record
+    nameid : longword;          //name offset / integer ID / languageID
+    ncount : longword;          //named sub-entries count
+    idcountsize : longword;     //id sub-entries count / resource size
+    subptr : longword;          //first sub-entry offset
+  end;
+
+const
+  EXTERNAL_RESMAGIC : TExternalResMagic = 'FPCRES';
+  
+  EXT_CURRENT_VERSION = 1;
+  
+  EXT_ENDIAN_BIG = 1;
+  EXT_ENDIAN_LITTLE = 2;
+
+
+implementation
+
+end.

+ 297 - 0
packages/fcl-res/src/externalwriter.pp

@@ -0,0 +1,297 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource writer for external resource types
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit externalwriter;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, resourcetree, externaltypes, strtable;
+  
+type
+  EExternalResourceWriterException = class(EResourceWriterException);
+  EExternalResInvalidEndianessException = class(EExternalResourceWriterException);
+
+type
+
+  { TExternalResourceWriter }
+
+  TExternalResourceWriter = class(TAbstractResourceWriter)
+  private
+    fExtensions : string;
+    fDescription : string;
+    fFileHeader : TExtHeader;
+    fRoot : TRootResTreeNode;
+    fEndianess : byte;
+    fOppositeEndianess : boolean;
+    fStrTable : TResStringTable;
+    fDataCurOfs : longword;
+
+    function NextAlignedQword(aValue : longword) : longword;
+    procedure AlignQword(aStream : TStream);
+
+    procedure PrescanResourceTree;
+    function PrescanNode(aNode : TResourceTreeNode) : longword;
+    procedure WriteEmptyFileHeader(aStream : TStream);
+    procedure WriteNodeInfos(aStream : TStream);
+    procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteSubNodes(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteStringTable(aStream : TStream);
+    procedure WriteRawData(aStream : TStream);
+    procedure WriteResData(aStream : TStream; aNode : TResourceTreeNode);
+    procedure FixHeader(aResources : TResources; aStream : TStream);
+    procedure SetEndianess(aEndianess : byte);
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Write(aResources : TResources; aStream : TStream); override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    property Endianess : byte read fEndianess write SetEndianess;
+  end;
+
+implementation
+
+{ TExternalResourceWriter }
+
+function TExternalResourceWriter.NextAlignedQword(aValue: longword): longword;
+var topad : longword;
+begin
+  Result:=aValue;
+  topad:=8-(aValue mod 8);
+  if topad<>8 then inc(Result,topad);
+end;
+
+procedure TExternalResourceWriter.AlignQword(aStream: TStream);
+var topad : integer;
+    qw : qword;
+begin
+  qw:=0;
+  topad:=8-(aStream.Position mod 8);
+  if topad<>8 then aStream.WriteBuffer(qw,topad);
+end;
+
+procedure TExternalResourceWriter.PrescanResourceTree;
+begin
+  fStrTable.Clear;
+  fRoot.SubDirRVA:=sizeof(TExtHeader)+sizeof(TResInfoNode);
+  fStrTable.StartOfs:=PrescanNode(fRoot);
+  if fStrTable.Used then
+    fDataCurOfs:=NextAlignedQword(fStrTable.StartOfs+fStrTable.Size)
+  else
+    fDataCurOfs:=fStrTable.StartOfs;
+  fFileHeader.nodesize:=fStrTable.StartOfs;
+  fFileHeader.hdrsize:=fDataCurOfs;
+end;
+
+function TExternalResourceWriter.PrescanNode(aNode: TResourceTreeNode
+  ): longword;
+var curofs : longword;
+    i : integer;
+    subnode : TResourceTreeNode;
+begin
+  if aNode.IsLeaf then
+  begin
+    Result:=aNode.SubDirRVA;
+    exit;
+  end;
+  
+  if aNode.Desc.DescType=dtName then
+    aNode.NameRVA:=fStrTable.Add(aNode.Desc.Name);
+
+  //first node subnodes begin at curofs (after all node headers)
+  curofs:=aNode.SubDirRva+(aNode.NamedCount+aNode.IDCount)*sizeof(TResInfoNode);
+  for i:=0 to aNode.NamedCount-1 do
+  begin
+    subnode:=aNode.NamedEntries[i];
+    subnode.SubDirRVA:=curofs;
+    curofs:=PrescanNode(subnode);
+  end;
+  for i:=0 to aNode.IDCount-1 do
+  begin
+    subnode:=aNode.IDEntries[i];
+    subnode.SubDirRVA:=curofs;
+    curofs:=PrescanNode(subnode);
+  end;
+  Result:=curofs;
+end;
+
+procedure TExternalResourceWriter.WriteEmptyFileHeader(aStream: TStream);
+begin
+  FillByte(fFileHeader,sizeof(fFileHeader),0);
+  aStream.WriteBuffer(fFileHeader,sizeof(fFileHeader));
+end;
+
+procedure TExternalResourceWriter.WriteNodeInfos(aStream: TStream);
+begin
+  WriteNodeInfo(aStream,fRoot);
+  WriteSubNodes(aStream,fRoot);
+end;
+
+procedure TExternalResourceWriter.WriteNodeInfo(aStream: TStream;
+  aNode: TResourceTreeNode);
+var infonode : TResInfoNode;
+begin
+  if aNode.Desc.DescType=dtID then
+    infonode.nameid:=aNode.Desc.ID
+  else
+    infonode.nameid:=fStrTable.StartOfs+aNode.NameRVA;
+  infonode.ncount:=aNode.NamedCount;
+  if aNode.IsLeaf then
+  begin
+    infonode.idcountsize:=aNode.Data.RawData.Size;
+    infonode.subptr:=fDataCurOfs;
+    fDataCurOfs:=NextAlignedQword(fDataCurOfs+infonode.idcountsize);
+  end
+  else
+  begin
+    infonode.idcountsize:=aNode.IDCount;
+    infonode.subptr:=aNode.SubDirRVA;
+  end;
+  if fOppositeEndianess then
+  begin
+    infonode.nameid:=SwapEndian(infonode.nameid);
+    infonode.ncount:=SwapEndian(infonode.ncount);
+    infonode.idcountsize:=SwapEndian(infonode.idcountsize);
+    infonode.subptr:=SwapEndian(infonode.subptr);
+  end;
+  aStream.WriteBuffer(infonode,sizeof(infonode));
+end;
+
+procedure TExternalResourceWriter.WriteSubNodes(aStream: TStream;
+  aNode: TResourceTreeNode);
+var i : integer;
+begin
+  for i:=0 to aNode.NamedCount-1 do
+    WriteNodeInfo(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteNodeInfo(aStream,aNode.IDEntries[i]);
+    
+  for i:=0 to aNode.NamedCount-1 do
+    WriteSubNodes(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteSubNodes(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TExternalResourceWriter.WriteStringTable(aStream: TStream);
+begin
+  if fStrTable.Used then
+    fStrTable.WriteToStream(aStream);
+  AlignQword(aStream);
+end;
+
+procedure TExternalResourceWriter.WriteRawData(aStream: TStream);
+begin
+  WriteResData(aStream,fRoot);
+end;
+
+procedure TExternalResourceWriter.WriteResData(aStream: TStream;
+  aNode: TResourceTreeNode);
+var rawdata : TStream;
+    i : integer;
+begin
+  if aNode.IsLeaf then
+  begin
+    rawdata:=aNode.Data.RawData;
+    rawdata.Position:=0;
+    aStream.CopyFrom(rawdata,rawdata.Size);
+    AlignQword(aStream);
+    exit;
+  end;
+  for i:=0 to aNode.NamedCount-1 do
+    WriteResData(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteResData(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TExternalResourceWriter.FixHeader(aResources : TResources;
+  aStream: TStream);
+var oldpos : int64;
+begin
+  fFileHeader.magic:=EXTERNAL_RESMAGIC;
+  fFileHeader.version:=EXT_CURRENT_VERSION;
+  fFileHeader.endianess:=fEndianess;
+  fFileHeader.count:=aResources.Count;
+  //nodesize and hdrsize have already been set
+  if fOppositeEndianess then
+  begin
+    fFileHeader.count:=SwapEndian(fFileHeader.count);
+    fFileHeader.nodesize:=SwapEndian(fFileHeader.nodesize);
+    fFileHeader.hdrsize:=SwapEndian(fFileHeader.hdrsize);
+  end;
+  oldpos:=aStream.Position;
+  aStream.Position:=0;
+  aStream.WriteBuffer(fFileHeader,sizeof(fFileHeader));
+  aStream.Position:=oldpos;
+end;
+
+procedure TExternalResourceWriter.SetEndianess(aEndianess: byte);
+begin
+  if not (aEndianess in [EXT_ENDIAN_BIG,EXT_ENDIAN_LITTLE]) then
+    raise EExternalResInvalidEndianessException.Create('');
+  if aEndianess=fEndianess then exit;
+  fEndianess:=aEndianess;
+  fOppositeEndianess:=not fOppositeEndianess;
+end;
+
+function TExternalResourceWriter.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TExternalResourceWriter.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TExternalResourceWriter.Write(aResources: TResources;
+  aStream: TStream);
+begin
+  WriteEmptyFileHeader(aStream);
+  fRoot:=TRootResTreeNode(GetTree(aResources));
+  PrescanResourceTree;
+  FixHeader(aResources,aStream);
+  WriteNodeInfos(aStream);
+  WriteStringTable(aStream);
+  WriteRawData(aStream);
+end;
+
+constructor TExternalResourceWriter.Create;
+begin
+  fRoot:=nil;
+  fExtensions:='.fpcres .frs';
+  fDescription:='External file resource writer';
+  {$IFDEF ENDIAN_BIG}
+  fEndianess:=EXT_ENDIAN_BIG;
+  {$ELSE}
+  fEndianess:=EXT_ENDIAN_LITTLE;
+  {$ENDIF}
+  fOppositeEndianess:=false;
+  fStrTable:=TResStringTable.Create;
+end;
+
+destructor TExternalResourceWriter.Destroy;
+begin
+  fStrTable.Free;
+end;
+
+initialization
+  TResources.RegisterWriter('.fpcres',TExternalResourceWriter);
+  TResources.RegisterWriter('.frs',TExternalResourceWriter);
+
+end.

+ 53 - 0
packages/fcl-res/src/fpcrestypes.pp

@@ -0,0 +1,53 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Common types used by various readers and writers
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit fpcrestypes;
+
+{$MODE OBJFPC}
+
+interface
+
+type
+  TResHdr32 = packed record
+    rootptr     : longword;     //pointer to root node
+    count       : longword;     //number of resources in the file
+    usedhandles : longword;     //set at runtime
+    handles     : longword;     //pointer to handles
+  end;
+
+  TResHdr64 = packed record
+    rootptr     : qword;        //pointer to root node
+    count       : longword;     //number of resources in the file
+    usedhandles : longword;     //set at runtime
+    handles     : qword;        //pointer to handles
+  end;
+
+  TResInfoNode32 = packed record
+    nameid : longword;          //name offset / integer ID / languageID
+    ncount : longword;          //named sub-entries count
+    idcountsize : longword;     //id sub-entries count / resource size
+    subptr : longword;          //first sub-entry offset
+  end;
+
+  TResInfoNode64 = packed record
+    nameid : qword;             //name offset / integer ID / languageID
+    ncount : longword;          //named sub-entries count
+    idcountsize : longword;     //id sub-entries count / resource size
+    subptr : qword;             //first sub-entry offset
+  end;
+
+implementation
+
+end.

+ 314 - 0
packages/fcl-res/src/groupcursorresource.pp

@@ -0,0 +1,314 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Group cursor resource type
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit groupcursorresource;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource, groupresource;
+  
+type
+
+  { TGroupCursorResource }
+
+  TGroupCursorResource = class(TGroupResource)
+  private
+    function WriteCurCursorHeader(aStream : TStream; const index : integer; const start : longword) : longword;
+  protected
+    procedure ReadResourceItemHeader; override;
+    procedure WriteHeader(aStream : TStream); override;
+    procedure CreateSubItem; override;
+    procedure UpdateItemOwner(index : integer); override;
+    procedure ClearItemList; override;
+    procedure DeleteSubItems; override;
+    function GetSubStream(const index : integer; out aSize : int64) : TStream; override;
+    function GetType : TResourceDesc; override;
+    function GetName : TResourceDesc; override;
+    function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
+    function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
+  public
+    constructor Create; override;
+    constructor Create(aType,aName : TResourceDesc); override;
+  end;
+
+implementation
+
+uses
+  resfactory, resdatastream, icocurtypes;
+  
+type
+  TCurInfo = record
+    res : TAbstractResource;
+    header : TResCursorDir;
+  end;
+  PCurInfo = ^TCurInfo;
+
+{ TGroupCursorResource }
+
+procedure TGroupCursorResource.ReadResourceItemHeader;
+var pci : PCurInfo;
+    res : TAbstractResource;
+    cursorid : word;
+begin
+  if OwnerList=nil then exit;
+  GetMem(pci,sizeof(TCurInfo));
+  try
+    RawData.ReadBuffer(pci^.header,sizeof(TResCursorDir));
+    cursorid:=pci^.header.cursorId;
+    {$IFDEF ENDIAN_BIG}
+    cursorId:=SwapEndian(cursorId);
+    {$ENDIF}
+    res:=OwnerList.Find(RT_CURSOR,cursorid,LangID);
+    pci^.res:=res;
+    SetChildOwner(res);
+    fItemList.Add(pci);
+   except
+     FreeMem(pci);
+     raise;
+   end;
+end;
+
+function TGroupCursorResource.WriteCurCursorHeader(aStream: TStream;
+  const index: integer; const start: longword): longword;
+var pci : PCurInfo;
+    hdr : TCurCursorDir;
+    tmpw,tmph : word;
+begin
+  pci:=PCurInfo(fItemList[index]);
+  tmpw:=pci^.header.width;
+  tmph:=pci^.header.height;
+  {$IFDEF ENDIAN_BIG}
+  tmpw:=SwapEndian(tmpw);
+  tmph:=SwapEndian(tmph);
+  {$ENDIF}
+  tmph:=tmph div 2;                    //in cursor resources, height is doubled.
+
+  hdr.width:=tmpw;                     //it's a byte now, no need to swap
+  hdr.height:=tmph;                    //it's a byte now, no need to swap
+  hdr.reserved:=0;
+  hdr.bytesincur:=pci^.header.bytesinres;
+  hdr.curoffset:=start;
+  pci^.res.RawData.Position:=0;
+  pci^.res.RawData.ReadBuffer(hdr.xhotspot,2);
+  pci^.res.RawData.ReadBuffer(hdr.yhotspot,2);
+  {$IFDEF ENDIAN_BIG}
+  hdr.curoffset:=SwapEndian(hdr.curoffset);
+  hdr.bytesincur:=SwapEndian(hdr.bytesincur);
+  {$ENDIF}
+  dec(hdr.bytesincur,4); //in resources, cursor has 2 words more for hotspots
+  {$IFDEF ENDIAN_BIG}
+  hdr.bytesincur:=SwapEndian(hdr.bytesincur);
+  {$ENDIF}
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+  Result:=start+pci^.res.RawData.Size-4;
+end;
+
+procedure TGroupCursorResource.WriteHeader(aStream: TStream);
+var nh : TNewHeader;
+    i : integer;
+    addrcount : longword;
+begin
+  //write CUR file header (identical to the resource cursor header)
+  nh.reserved:=0;
+  nh.restype:=RES_CURSOR;
+  nh.rescount:=fItemList.Count;
+  {$IFDEF ENDIAN_BIG}
+  nh.reserved:=SwapEndian(nh.reserved);
+  nh.restype:=SwapEndian(nh.restype);
+  nh.rescount:=SwapEndian(nh.rescount);
+  {$ENDIF}
+  aStream.Position:=0;
+  aStream.WriteBuffer(nh,sizeof(nh));
+  addrcount:=sizeof(TNewHeader)+sizeof(TCurCursorDir)*fItemList.Count;
+  for i:=0 to fItemList.Count-1 do
+    addrcount:=WriteCurCursorHeader(aStream,i,addrcount);
+end;
+
+procedure TGroupCursorResource.ClearItemList;
+var pci : PCurInfo;
+    i : integer;
+begin
+  if fItemList=nil then exit;
+  for i:=0 to fItemList.Count-1 do
+  begin
+    pci:=PCurInfo(fItemList[i]);
+     //if we are not in a TResources, free all subitems by ourselves.
+    if OwnerList=nil then pci^.res.Free;
+    FreeMem(pci);
+  end;
+  fItemList.Clear;
+end;
+
+procedure TGroupCursorResource.DeleteSubItems;
+var pci : PCurInfo;
+    i : integer;
+begin
+  if fItemList=nil then exit;
+  for i:=0 to fItemList.Count-1 do
+  begin
+    pci:=PCurInfo(fItemList[i]);
+    if OwnerList<>nil then
+      OwnerList.Remove(pci^.res);
+    pci^.res.Free;
+    FreeMem(pci);
+  end;
+  fItemList.Clear;
+end;
+
+procedure TGroupCursorResource.CreateSubItem;
+var res : TAbstractResource;
+    pci : PCurInfo;
+    curhdr : TCurCursorDir;
+    oldpos : int64;
+    bytesinres : longword;
+    curoffset : longword;
+    index : word;
+begin
+  index:=fItemList.Count+1;
+  dummyName.ID:=index;
+  res:=TResourceFactory.CreateResource(dummyType,dummyName);
+  res.LangID:=LangID;
+  if OwnerList<>nil then
+    index:=OwnerList.AddAutoID(res);
+
+  GetMem(pci,sizeof(TCurInfo));
+  fItemList.Add(pci);
+  pci^.res:=res;
+  ItemData.ReadBuffer(curhdr,sizeof(TCurCursorDir));
+  pci^.header.width:=curhdr.width;     //it was a byte, no need to swap
+  pci^.header.height:=curhdr.height*2; //in cursor resources, height is doubled.
+  pci^.header.planes:=1;
+  pci^.header.bitcount:=1;
+  pci^.header.cursorId:=index;
+  bytesinres:=curhdr.bytesincur;
+  curoffset:=curhdr.curoffset;
+  {$IFDEF ENDIAN_BIG}
+  bytesinres:=SwapEndian(bytesinres);
+  curoffset:=SwapEndian(curoffset);
+  {$ENDIF}
+  oldpos:=ItemData.Position;
+  try
+    ItemData.Position:=curoffset;
+    res.RawData.Size:=0;
+    res.RawData.Position:=0;
+    res.RawData.WriteBuffer(curhdr.xhotspot,2);
+    res.RawData.WriteBuffer(curhdr.yhotspot,2);
+    res.RawData.CopyFrom(ItemData,bytesinres);
+  finally
+    ItemData.Position:=oldpos;
+  end;
+  inc(bytesinres,4);       //in resources, cursor has 2 words more for hotspots
+  pci^.header.bytesinres:=bytesinres;
+  {$IFDEF ENDIAN_BIG}
+  pci^.header.width:=SwapEndian(pci^.header.width);
+  pci^.header.height:=SwapEndian(pci^.header.height);
+  pci^.header.planes:=SwapEndian(pci^.header.planes);
+  pci^.header.bitcount:=SwapEndian(pci^.header.bitcount);
+  pci^.header.bytesinres:=SwapEndian(pci^.header.bytesinres);
+  pci^.header.cursorId:=SwapEndian(pci^.header.cursorId);
+  {$ENDIF}
+  RawData.WriteBuffer(pci^.header,sizeof(TResCursorDir));
+end;
+
+procedure TGroupCursorResource.UpdateItemOwner(index: integer);
+var pci : PCurInfo;
+    theid : word;
+    oldpos : int64;
+begin
+  pci:=PCurInfo(fItemList[index]);
+  if pci^.res.OwnerList=OwnerList then exit;
+  if OwnerList=nil then
+  begin
+    pci^.res.OwnerList.Remove(pci^.res);
+    exit;
+  end;
+  theid:=pci^.res.Name.ID;
+  OwnerList.AddAutoID(pci^.res);
+  if theid<>pci^.res.Name.ID then //id changed, update
+  begin
+    theid:=pci^.res.Name.ID;
+    pci^.header.cursorId:=theid; //update header id value
+    {$IFDEF ENDIAN_BIG}
+    pci^.header.cursorId:=SwapEndian(pci^.header.cursorId);
+    {$ENDIF}
+    //update id in rawdata (ItemStream, if present, is ok)
+    if (fItemData=nil) or TResourceDataStream(ItemData).Cached then
+    begin
+      oldpos:=RawData.Position;
+      try
+        RawData.Position:=sizeof(TNewHeader)+(index+1)*sizeof(TResCursorDir)-2;
+        RawData.WriteBuffer(pci^.header.cursorId,2);
+      finally
+        RawData.Position:=oldpos;
+      end;
+    end;
+  end;
+end;
+
+function TGroupCursorResource.GetSubStream(const index: integer; out aSize : int64): TStream;
+begin
+  Result:=PCurInfo(fItemList[index])^.res.RawData;
+  Result.Position:=4;
+  aSize:=Result.Size-4;
+end;
+
+function TGroupCursorResource.GetType: TResourceDesc;
+begin
+  Result:=fType;
+end;
+
+function TGroupCursorResource.GetName: TResourceDesc;
+begin
+  Result:=fName;
+end;
+
+function TGroupCursorResource.ChangeDescTypeAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+function TGroupCursorResource.ChangeDescValueAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+constructor TGroupCursorResource.Create;
+begin
+  inherited Create;
+  fItemList:=nil;
+  fItemData:=nil;
+  fType:=TResourceDesc.Create(RT_GROUP_CURSOR);
+  fName:=TResourceDesc.Create(1);
+  SetDescOwner(fType);
+  SetDescOwner(fName);
+  dummyType:=TResourceDesc.Create(RT_CURSOR);
+  dummyName:=TResourceDesc.Create(1);
+end;
+
+constructor TGroupCursorResource.Create(aType, aName: TResourceDesc);
+begin
+  Create;
+  fName.Assign(aName);
+end;
+
+initialization
+  TResourceFactory.RegisterResourceClass(RT_GROUP_CURSOR,TGroupCursorResource);
+
+end.

+ 284 - 0
packages/fcl-res/src/groupiconresource.pp

@@ -0,0 +1,284 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Group icon resource type
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit groupiconresource;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource, groupresource;
+  
+type
+
+  { TGroupIconResource }
+
+  TGroupIconResource = class(TGroupResource)
+  private
+    function WriteIcoIconHeader(aStream : TStream; const index : integer; const start : longword) : longword;
+  protected
+    procedure ReadResourceItemHeader; override;
+    procedure WriteHeader(aStream : TStream); override;
+    procedure CreateSubItem; override;
+    procedure UpdateItemOwner(index : integer); override;
+    procedure ClearItemList; override;
+    procedure DeleteSubItems; override;
+    function GetSubStream(const index : integer; out aSize : int64) : TStream; override;
+    function GetType : TResourceDesc; override;
+    function GetName : TResourceDesc; override;
+    function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
+    function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
+  public
+    constructor Create; override;
+    constructor Create(aType,aName : TResourceDesc); override;
+  end;
+
+
+implementation
+
+uses
+  resfactory, resdatastream, icocurtypes;
+
+type
+  TIconInfo = record
+    res : TAbstractResource;
+    header : TIconDir;
+  end;
+  PIconInfo = ^TIconInfo;
+
+{ TGroupIconResource }
+
+procedure TGroupIconResource.ReadResourceItemHeader;
+var pii : PIconInfo;
+    res : TAbstractResource;
+    offsetid : longword;
+begin
+  if OwnerList=nil then exit;
+  GetMem(pii,sizeof(TIconInfo));
+  try
+   //TIconDir is slightly different in resources and in .ico files
+    pii^.header.offsetId:=0;
+    RawData.ReadBuffer(pii^.header,sizeof(TIconDir)-2);
+    offsetid:=pii^.header.offsetId;
+    {$IFDEF ENDIAN_BIG}
+    offsetId:=SwapEndian(offsetId);
+    {$ENDIF}
+    res:=OwnerList.Find(RT_ICON,offsetID,LangID);
+    pii^.res:=res;
+    SetChildOwner(res);
+    fItemList.Add(pii);
+   except
+     FreeMem(pii);
+     raise;
+   end;
+end;
+
+function TGroupIconResource.WriteIcoIconHeader(aStream : TStream;
+  const index : integer; const start : longword) : longword;
+var pii : PIconInfo;
+    hdr : TIconDir;
+begin
+  pii:=PIconInfo(fItemList[index]);
+  hdr:=pii^.header;
+  hdr.offsetId:=start;
+  {$IFDEF ENDIAN_BIG}
+  hdr.offsetId:=SwapEndian(hdr.offsetId);
+  {$ENDIF}
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+  Result:=start+pii^.res.RawData.Size;
+end;
+
+procedure TGroupIconResource.WriteHeader(aStream: TStream);
+var nh : TNewHeader;
+    i : integer;
+    addrcount : longword;
+begin
+  //write ICO file header (identical to the resource icon header)
+  nh.reserved:=0;
+  nh.restype:=RES_ICON;
+  nh.rescount:=fItemList.Count;
+  {$IFDEF ENDIAN_BIG}
+  nh.reserved:=SwapEndian(nh.reserved);
+  nh.restype:=SwapEndian(nh.restype);
+  nh.rescount:=SwapEndian(nh.rescount);
+  {$ENDIF}
+  aStream.Position:=0;
+  aStream.WriteBuffer(nh,sizeof(nh));
+  addrcount:=sizeof(TNewHeader)+sizeof(TIconDir)*fItemList.Count;
+  for i:=0 to fItemList.Count-1 do
+    addrcount:=WriteIcoIconHeader(aStream,i,addrcount);
+end;
+
+procedure TGroupIconResource.ClearItemList;
+var pii : PIconInfo;
+    i : integer;
+begin
+  if fItemList=nil then exit;
+  for i:=0 to fItemList.Count-1 do
+  begin
+    pii:=PIconInfo(fItemList[i]);
+     //if we are not in a TResources, free all subitems by ourselves.
+    if OwnerList=nil then pii^.res.Free;
+    FreeMem(pii);
+  end;
+  fItemList.Clear;
+end;
+
+procedure TGroupIconResource.DeleteSubItems;
+var pii : PIconInfo;
+    i : integer;
+begin
+  if fItemList=nil then exit;
+  for i:=0 to fItemList.Count-1 do
+  begin
+    pii:=PIconInfo(fItemList[i]);
+    if OwnerList<>nil then
+      OwnerList.Remove(pii^.res);
+    pii^.res.Free;
+    FreeMem(pii);
+  end;
+  fItemList.Clear;
+end;
+
+procedure TGroupIconResource.CreateSubItem;
+var res : TAbstractResource;
+    pii : PIconInfo;
+    oldpos : int64;
+    bytesinres : longword;
+    offsetid : longword;
+    index : word;
+begin
+  index:=fItemList.Count+1;
+  dummyName.ID:=index;
+  res:=TResourceFactory.CreateResource(dummyType,dummyName);
+  res.LangID:=LangID;
+  if OwnerList<>nil then
+    index:=OwnerList.AddAutoID(res);
+    
+  GetMem(pii,sizeof(TIconInfo));
+  fItemList.Add(pii);
+  pii^.res:=res;
+  ItemData.ReadBuffer(pii^.header,sizeof(TIconDir));
+  bytesinres:=pii^.header.bytesinres;
+  offsetid:=pii^.header.offsetid;
+  {$IFDEF ENDIAN_BIG}
+  bytesinres:=SwapEndian(bytesinres);
+  offsetID:=SwapEndian(offsetID);
+  {$ENDIF}
+  oldpos:=ItemData.Position;
+  try
+    ItemData.Position:=offsetid;
+    res.RawData.Size:=0;
+    res.RawData.Position:=0;
+    res.RawData.CopyFrom(ItemData,bytesinres);
+  finally
+    ItemData.Position:=oldpos;
+  end;
+  pii^.header.offsetId:=index;
+  {$IFDEF ENDIAN_BIG}
+  pii^.header.offsetID:=SwapEndian(pii^.header.offsetID);
+  {$ENDIF}
+   //TIconDir is slightly different in resources and in .ico files
+  RawData.WriteBuffer(pii^.header,sizeof(TIconDir)-2);
+end;
+
+procedure TGroupIconResource.UpdateItemOwner(index: integer);
+var pii : PIconInfo;
+    theid : longword;
+    oldpos : int64;
+begin
+  pii:=PIconInfo(fItemList[index]);
+  if pii^.res.OwnerList=OwnerList then exit;
+  if OwnerList=nil then
+  begin
+    pii^.res.OwnerList.Remove(pii^.res);
+    exit;
+  end;
+  theid:=pii^.res.Name.ID;
+  OwnerList.AddAutoID(pii^.res);
+  if theid<>pii^.res.Name.ID then //id changed, update
+  begin
+    theid:=pii^.res.Name.ID;
+    pii^.header.offsetId:=theid; //update header id value
+    {$IFDEF ENDIAN_BIG}
+    pii^.header.offsetID:=SwapEndian(pii^.header.offsetID);
+    {$ENDIF}
+    //update id in rawdata (ItemStream, if present, is ok)
+    if (fItemData=nil) or TResourceDataStream(ItemData).Cached then
+    begin
+      oldpos:=RawData.Position;
+      try
+        RawData.Position:=sizeof(TNewHeader)+(index+1)*(sizeof(TIconDir)-2)-2;
+        RawData.WriteBuffer(pii^.header.offsetID,2); //update id (it's a word)
+      finally
+        RawData.Position:=oldpos;
+      end;
+    end;
+  end;
+end;
+
+function TGroupIconResource.GetSubStream(const index: integer; out aSize : int64): TStream;
+begin
+  Result:=PIconInfo(fItemList[index])^.res.RawData;
+  Result.Position:=0;
+  aSize:=Result.Size;
+end;
+
+function TGroupIconResource.GetType: TResourceDesc;
+begin
+  Result:=fType;
+end;
+
+function TGroupIconResource.GetName: TResourceDesc;
+begin
+  Result:=fName;
+end;
+
+function TGroupIconResource.ChangeDescTypeAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+function TGroupIconResource.ChangeDescValueAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+constructor TGroupIconResource.Create;
+begin
+  inherited Create;
+  fItemList:=nil;
+  fItemData:=nil;
+  fType:=TResourceDesc.Create(RT_GROUP_ICON);
+  fName:=TResourceDesc.Create(1);
+  SetDescOwner(fType);
+  SetDescOwner(fName);
+  dummyType:=TResourceDesc.Create(RT_ICON);
+  dummyName:=TResourceDesc.Create(1);
+end;
+
+constructor TGroupIconResource.Create(aType, aName: TResourceDesc);
+begin
+  Create;
+  fName.Assign(aName);
+end;
+
+initialization
+  TResourceFactory.RegisterResourceClass(RT_GROUP_ICON,TGroupIconResource);
+
+end.

+ 268 - 0
packages/fcl-res/src/groupresource.pp

@@ -0,0 +1,268 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Base classes for group cursor and group icon resource types
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit groupresource;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource, resdatastream;
+
+type
+
+  { TGroupResource }
+
+  TGroupResource = class(TAbstractResource)
+  protected
+    fType : TResourceDesc;
+    fName : TResourceDesc;
+    fItemData : TStream;
+    fItemList : TFPList;
+    dummyType : TResourceDesc;
+    dummyName : TResourceDesc;
+    procedure FindSubResources;
+    procedure ReadResourceItemHeader; virtual; abstract;
+    procedure CheckBuildItemStream;
+    function GetItemData : TStream;
+    procedure WriteHeader(aStream : TStream); virtual; abstract;
+    function WriteResHeader : word;
+    procedure CreateSubItems;
+    procedure CreateSubItem; virtual; abstract;
+    procedure UpdateItemOwner(index : integer); virtual; abstract;
+    procedure ClearItemList; virtual; abstract;
+    procedure DeleteSubItems; virtual; abstract;
+    function GetSubStreamCount : integer;
+    function GetSubStream(const index : integer; out aSize : int64) : TStream; virtual; abstract;
+    procedure SetOwnerList(aResources : TResources); override;
+    procedure NotifyResourcesLoaded; override;
+  public
+    destructor Destroy; override;
+    function CompareContents(aResource: TAbstractResource): boolean; override;
+    procedure SetCustomItemDataStream(aStream : TStream);
+    procedure UpdateRawData; override;
+    property ItemData : TStream read GetItemData;
+  end;
+
+  { TGroupCachedDataStream }
+
+  TGroupCachedDataStream = class(TCachedDataStream)
+  private
+    fHeader : TMemoryStream;
+    fStreams : TFPList;
+    function ReadFromSubStream(aStream : TStream; var Buffer; aPosition : int64; aCount : longint) : longint;
+  protected
+  public
+    constructor Create(aStream : TStream;  aResource : TAbstractResource; aSize : int64); override;
+    destructor Destroy; override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+  end;
+
+implementation
+
+uses
+  icocurtypes;
+
+{ TGroupResource }
+
+procedure TGroupResource.FindSubResources;
+var nh : TNewHeader;
+    i : integer;
+begin
+  if fItemList<>nil then exit;
+  fItemList:=TFPList.Create;
+  //read NewHeader from resource
+  RawData.Position:=0;
+  try
+    RawData.ReadBuffer(nh,sizeof(nh));
+  except
+    on e : EReadError do exit; //empty stream
+  end;
+  {$IFDEF ENDIAN_BIG}
+  nh.reserved:=SwapEndian(nh.reserved);
+  nh.restype:=SwapEndian(nh.restype);
+  nh.rescount:=SwapEndian(nh.rescount);
+  {$ENDIF}
+  for i:=1 to nh.rescount do
+    ReadResourceItemHeader;
+end;
+
+procedure TGroupResource.CheckBuildItemStream;
+begin
+  if fItemData<>nil then exit;
+  FindSubResources;
+  fItemData:=TResourceDataStream.Create(RawData,self,DataSize,TGroupCachedDataStream);
+end;
+
+function TGroupResource.GetItemData: TStream;
+begin
+  CheckBuildItemStream;
+  Result:=fItemData;
+end;
+
+function TGroupResource.WriteResHeader: word;
+var nh : TNewHeader;
+begin
+  //copy RES header from the ICO/CUR one (they are identical)
+  ItemData.Position:=0;
+  ItemData.ReadBuffer(nh,sizeof(nh));
+  RawData.Size:=0;
+  RawData.Position:=0;
+  RawData.WriteBuffer(nh,sizeof(nh));
+  Result:=nh.rescount;
+  {$IFDEF ENDIAN_BIG}
+  Result:=SwapEndian(Result);
+  {$ENDIF}
+end;
+
+procedure TGroupResource.CreateSubItems;
+var itemcount : word;
+    i : integer;
+begin
+  if fItemList=nil then fItemList:=TFPList.Create;
+  itemcount:=WriteResHeader;
+  for i:=1 to itemcount do
+    CreateSubItem;
+end;
+
+function TGroupResource.GetSubStreamCount: integer;
+begin
+  Result:=fItemList.Count;
+end;
+
+procedure TGroupResource.SetOwnerList(aResources: TResources);
+var i : integer;
+begin
+  inherited SetOwnerList(aResources);
+  if fItemList=nil then exit;
+  for i:=0 to fItemList.Count-1 do
+    UpdateItemOwner(i);
+end;
+
+procedure TGroupResource.NotifyResourcesLoaded;
+begin
+  //all resources have been loaded, so find all sub resources and tell them
+  //we are the owners
+  FindSubResources;
+end;
+
+destructor TGroupResource.Destroy;
+begin
+  if fItemData<>nil then fItemData.Free;
+  ClearItemList;
+  fItemList.Free;
+  fType.Free;
+  fName.Free;
+  dummyType.Free;
+  dummyName.Free;
+  inherited Destroy;
+end;
+
+function TGroupResource.CompareContents(aResource: TAbstractResource): boolean;
+begin
+  if aResource is TGroupResource then
+    Result:=TResourceDataStream(ItemData).Compare(TGroupResource(aResource).ItemData)
+  else
+    Result:=inherited CompareContents(aResource);
+end;
+
+procedure TGroupResource.SetCustomItemDataStream(aStream: TStream);
+begin
+  TResourceDataStream(ItemData).SetCustomStream(aStream);
+end;
+
+procedure TGroupResource.UpdateRawData;
+begin
+  if (fItemData=nil) or  TResourceDataStream(ItemData).Cached then exit; //no need to update rawdata
+  DeleteSubItems;
+  CreateSubItems;
+  FreeAndNil(fItemData);
+end;
+
+  { TGroupCachedDataStream }
+
+function TGroupCachedDataStream.ReadFromSubStream(aStream: TStream;
+  var Buffer; aPosition: int64; aCount: longint): longint;
+var oldpos : int64;
+begin
+  Result:=aStream.Size-aPosition;
+  if aCount<Result then Result:=aCount;
+  if Result<0 then Result:=0;
+  oldpos:=aStream.Position;
+  aStream.Position:=aPosition;
+  Result:=aStream.Read(Buffer,Result);
+  aStream.Position:=oldpos;
+end;
+
+constructor TGroupCachedDataStream.Create(aStream: TStream;  aResource : TAbstractResource; aSize: int64);
+var i, strcount : integer;
+    tmpstr : TStream;
+begin
+  inherited Create(aStream,aResource,aSize);
+  fHeader:=TMemoryStream.Create;
+  fStreams:=TFPList.Create;
+  TGroupResource(aResource).WriteHeader(fHeader);
+  strcount:=TGroupResource(aResource).GetSubStreamCount;
+  fSize:=fHeader.Size;
+  for i:=0 to strcount-1 do
+  begin
+    tmpstr:=TGroupResource(aResource).GetSubStream(i,aSize);
+    tmpstr:=TCachedResourceDataStream.Create(tmpstr,aResource,aSize);
+    fStreams.Add(tmpstr);
+    inc(fSize,aSize);
+  end;
+end;
+
+destructor TGroupCachedDataStream.Destroy;
+var i : integer;
+begin
+  for i:=0 to fStreams.Count-1 do
+    TStream(fStreams[i]).Free; //free the cached streams
+  fStreams.Free;
+  fHeader.Free;
+end;
+
+function TGroupCachedDataStream.Read(var Buffer; Count: Longint): Longint;
+var toread,read_in,delta : longint;
+    b : pbyte;
+    i : integer;
+begin
+  Result:=0;
+  toread:=fSize-Position;
+  if Count<toread then toread:=Count;
+  if toread<0 then toread:=0;
+  b:=@buffer;
+
+  read_in:=ReadFromSubStream(fHeader,b^,fPosition,toread);
+  inc(fPosition,read_in);
+  inc(b,read_in);
+  inc(Result,read_in);
+  dec(toread,read_in);
+  delta:=fHeader.Size;
+
+  for i:=0 to fStreams.Count-1 do
+  begin
+    if toread<=0 then exit;
+    read_in:=ReadFromSubStream(TStream(fStreams[i]),b^,fPosition-delta,toread);
+    inc(fPosition,read_in);
+    inc(b,read_in);
+    inc(Result,read_in);
+    dec(toread,read_in);
+    inc(delta,TStream(fStreams[i]).Size);
+  end;
+end;
+
+end.

+ 65 - 0
packages/fcl-res/src/icocurtypes.pp

@@ -0,0 +1,65 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Common types used by group icon and group cursor resource types
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit icocurtypes;
+
+{$MODE OBJFPC}
+
+interface
+
+const
+  RES_ICON   = 1;
+  RES_CURSOR = 2;
+
+type
+  TNewHeader = packed record
+    reserved : word;
+    restype  : word;
+    rescount : word;
+  end;
+
+  TIconDir = packed record
+    width      : byte;
+    height     : byte;
+    colorcount : byte;
+    reserved   : byte;
+    planes     : word;
+    bitcount   : word;
+    bytesinres : longword;
+    offsetId   : longword;
+  end;
+
+  TResCursorDir = packed record
+    width      : word;
+    height     : word;
+    planes     : word;
+    bitcount   : word;
+    bytesinres : longword;
+    cursorId   : word;
+  end;
+
+  TCurCursorDir = packed record
+    width      : byte;
+    height     : byte;
+    reserved   : word;
+    xhotspot   : word;
+    yhotspot   : word;
+    bytesincur : longword;
+    curoffset  : longword;
+  end;
+
+implementation
+
+end.

+ 203 - 0
packages/fcl-res/src/machoconsts.pp

@@ -0,0 +1,203 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Constants used by Mach-O resource reader and writer
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit machoconsts;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  machotypes;
+
+const
+  DataSegName     : TSegSectName = '__DATA'+#0+#0+#0+#0+#0+#0+#0+#0+#0+#0;
+  RsrcSectName    : TSegSectName = 'fpc.resources'+#0+#0+#0;
+  HandlesSectName : TSegSectName = 'fpc.reshandles'+#0+#0;
+  
+  //private constants used by reader and writer only, not apple-defined
+  MACH_BIG_ENDIAN = 1;
+  MACH_LITTLE_ENDIAN = 2;
+
+  MACH_ERRBIT = 0;
+  MACH_32BIT = 1;
+  MACH_64BIT = 2;
+  //end of private constants
+
+  //Mach-O magic numbers
+  MH_MAGIC    = $FEEDFACE;
+  MH_MAGIC_64 = $FEEDFACF;
+  MH_CIGAM    = $CEFAEDFE;
+  MH_CIGAM_64 = $CFFAEDFE;
+
+  //Cpu types
+  CPU_ARCH_ABI64     = $1000000;
+  CPU_TYPE_ANY       = -1;
+  CPU_TYPE_I386      = 7;
+  CPU_TYPE_X86_64    = CPU_TYPE_I386 or CPU_ARCH_ABI64;
+//  CPU_TYPE_ARM       = 12;
+  CPU_TYPE_POWERPC   = 18;
+  CPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC or CPU_ARCH_ABI64;
+
+  //Cpu subtypes
+  CPU_SUBTYPE_I386_ALL    = 3;
+  CPU_SUBTYPE_X86_64_ALL  = CPU_SUBTYPE_I386_ALL;
+  CPU_SUBTYPE_POWERPC_ALL = 0;
+
+  //Mach-O object types
+  MH_OBJECT      = $1;            // relocatable object file
+  MH_EXECUTE     = $2;            // demand paged executable file
+  MH_FVMLIB      = $3;            // fixed VM shared library file
+  MH_CORE        = $4;            // core file
+  MH_PRELOAD     = $5;            // preloaded executable file
+  MH_DYLIB       = $6;            // dynamically bound shared library
+  MH_DYLINKER    = $7;            // dynamic link editor
+  MH_BUNDLE      = $8;            // dynamically bound bundle file
+  MH_DYLIB_STUB  = $9;            // shared library stub for static
+                                  //  linking only, no section contents
+  //Mach-O object flags
+
+  MH_NOUNDEFS                = $00001;
+  MH_INCRLINK                = $00002;
+  MH_DYLDLINK                = $00004;
+  MH_BINDATLOAD              = $00008;
+  MH_PREBOUND                = $00010;
+  MH_SPLIT_SEGS              = $00020;
+  MH_TWOLEVEL                = $00080;
+  MH_FORCE_FLAT              = $00100;
+  MH_NOMULTIDEFS             = $00200;
+  MH_NOFIXPREBINDING         = $00400;
+  MH_PREBINDABLE             = $00800;
+  MH_ALLMODSBOUND            = $01000;
+  MH_SUBSECTIONS_VIA_SYMBOLS = $02000;
+  MH_CANONICAL               = $04000;
+  MH_WEAK_DEFINES            = $08000;
+  MH_BINDS_TO_WEAK           = $10000;
+
+  //Load commands
+
+  LC_SEGMENT        = $1;    // segment of this file to be mapped
+  LC_SYMTAB         = $2;    // link-edit stab symbol table info
+  LC_SYMSEG         = $3;    // link-edit gdb symbol table info (obsolete)
+  LC_THREAD         = $4;    // thread
+  LC_UNIXTHREAD     = $5;    // unix thread (includes a stack)
+  LC_LOADFVMLIB     = $6;    // load a specified fixed VM shared library
+  LC_IDFVMLIB       = $7;    // fixed VM shared library identification
+  LC_DYSYMTAB       = $b;    // dynamic link-edit symbol table info
+  LC_LOAD_DYLIB     = $c;    // load a dynamically linked shared library
+  LC_ID_DYLIB       = $d;    // dynamically linked shared lib ident
+  LC_LOAD_DYLINKER  = $e;    // load a dynamic linker
+  LC_ID_DYLINKER    = $f;    // dynamic linker identification
+  LC_PREBOUND_DYLIB = $10;   // modules prebound for a dynamically
+                             //  linked shared library
+  LC_ROUTINES       = $11;   // image routines
+  LC_SUB_FRAMEWORK  = $12;   // sub framework
+  LC_SUB_UMBRELLA   = $13;   // sub umbrella
+  LC_SUB_CLIENT     = $14;   // sub client
+  LC_SUB_LIBRARY    = $15;   // sub library
+  LC_TWOLEVEL_HINTS = $16;   // two-level namespace lookup hints
+  LC_PREBIND_CKSUM  = $17;   // prebind checksum
+  LC_LOAD_WEAK_DYLIB= $80000018;
+  LC_SEGMENT_64     = $19;   // 64-bit segment of this file to be mapped
+  LC_ROUTINES_64    = $1a;   // 64-bit image routines
+  LC_UUID           = $1b;   // the uuid
+  
+  //Segment: virtual memory protection
+  VM_PROT_NONE       = $00;
+  VM_PROT_READ       = $01;                // read permission
+  VM_PROT_WRITE      = $02;                // write permission
+  VM_PROT_EXECUTE    = $04;                // execute permission
+  VM_PROT_DEFAULT    = VM_PROT_READ or VM_PROT_WRITE;
+  VM_PROT_ALL        = VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE;
+  VM_PROT_NO_CHANGE  = $08;
+  VM_PROT_COPY       = $10;
+  VM_PROT_WANTS_COPY = $10;
+  
+  //Segment flags
+  SG_HIGHVM  = $01;
+  SG_FVMLIB  = $02;
+  SG_NORELOC = $04;
+  
+  //Section type and attributes masks
+  SECTION_TYPE       = $000000ff;    // 256 section types
+  SECTION_ATTRIBUTES = $ffffff00;    //  24 section attributes
+
+  //Section types
+  S_REGULAR                  = $0;
+  S_ZEROFILL                 = $1;
+  S_CSTRING_LITERALS         = $2;
+  S_4BYTE_LITERALS           = $3;
+  S_8BYTE_LITERALS           = $4;
+  S_LITERAL_POINTERS         = $5;
+  S_NON_LAZY_SYMBOL_POINTERS = $6;
+  S_LAZY_SYMBOL_POINTERS     = $7;
+  S_SYMBOL_STUBS             = $8;
+  S_MOD_INIT_FUNC_POINTERS   = $9;
+  S_MOD_TERM_FUNC_POINTERS   = $a;
+  S_COALESCED                = $b;
+  S_GB_ZEROFILL              = $c;
+  S_INTERPOSING              = $d;
+
+  //Section attributes
+  SECTION_ATTRIBUTES_USR   = $ff000000;
+  S_ATTR_PURE_INSTRUCTIONS = $80000000;
+  S_ATTR_NO_TOC            = $40000000;
+  S_ATTR_STRIP_STATIC_SYMS = $20000000;
+  S_ATTR_NO_DEAD_STRIP     = $10000000;
+  S_ATTR_LIVE_SUPPORT      = $08000000;
+  SECTION_ATTRIBUTES_SYS   = $00ffff00;
+  S_ATTR_SOME_INSTRUCTIONS = $00000400;
+  S_ATTR_EXT_RELOC         = $00000200;
+  S_ATTR_LOC_RELOC         = $00000100;
+
+  //Symbols: masks for type
+  N_STAB = $e0;  // if any of these bits set, a symbolic debugging entry
+  N_PEXT = $10;  // private external symbol bit
+  N_TYPE = $0e;  // mask for the type bits
+  N_EXT  = $01;  // external symbol bit, set for external symbols
+
+  //values for type in the N_TYPE bits
+  N_UNDF = $0;             // undefined, n_sect == NO_SECT
+  N_ABS  = $2;             // absolute, n_sect == NO_SECT
+  N_SECT = $e;             // defined in section number n_sect
+  N_PBUD = $c;             // prebound undefined (defined in a dylib)
+  N_INDR = $a;             // indirect
+  
+  //Relocations: masks for flag
+  R_SYMBOLNUM_BE = $FFFFFF00;
+  R_PCREL_BE     = $00000080;
+  R_LENGTH_BE    = $00000060;
+  R_EXTERN_BE    = $00000010;
+  R_TYPE_BE      = $0000000F;
+
+  R_SYMBOLNUM_LE = $00FFFFFF;
+  R_PCREL_LE     = $01000000;
+  R_LENGTH_LE    = $06000000;
+  R_EXTERN_LE    = $08000000;
+  R_TYPE_LE      = $F0000000;
+
+  //relocation types - powerpc
+  PPC_RELOC_VANILLA = 0;      // generic relocation
+
+  //relocation types - i386
+  GENERIC_RELOC_VANILLA = 0;  // generic relocation
+
+  //relocation types - x86_64
+  X86_64_RELOC_UNSIGNED = 0;  // for absolute addresses
+
+
+implementation
+
+end.

+ 45 - 0
packages/fcl-res/src/machodefaulttarget.inc

@@ -0,0 +1,45 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Default Mach-O target parameters
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+  fMachineType:=mmtpowerpc; //default
+  {$IFDEF CPUPOWERPC32}
+  fMachineType:=mmtpowerpc;
+  {$ENDIF}
+  {$IFDEF CPUPOWERPC64}
+  fMachineType:=mmtpowerpc64;
+  {$ENDIF}
+  {$IFDEF CPUI386}
+  fMachineType:=mmti386;
+  {$ENDIF}
+  {$IFDEF CPUX86_64}
+  fMachineType:=mmtx86_64;
+  {$ENDIF}
+
+  fBits:=MACH_ERRBIT;
+  {$IFDEF CPU32}
+  fBits:=MACH_32BIT;
+  {$ENDIF}
+  {$IFDEF CPU64}
+  fBits:=MACH_64BIT;
+  {$ENDIF}
+
+  {$IFDEF ENDIAN_BIG}
+  fNativeEndianess:=MACH_BIG_ENDIAN;
+  {$ELSE}
+  fNativeEndianess:=MACH_LITTLE_ENDIAN;
+  {$ENDIF}
+  fEndianess:=fNativeEndianess;
+  fOppositeEndianess:=false;
+

+ 290 - 0
packages/fcl-res/src/machoreader.pp

@@ -0,0 +1,290 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for Mach-O files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit machoreader;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, machotypes;
+  
+type
+
+  { TMachOResourceReader }
+
+  TMachOResourceReader = class (TAbstractResourceReader)
+  private
+    fDescription: string;
+    fExtensions: string;
+    fNativeEndianess : integer;
+    fEndianess : integer;
+    fOppositeEndianess : boolean;
+    fMachineType : TMachOMachineType;
+    fBits : integer;
+    fHeader : TMachHdr;
+    procedure SetDefaultTarget;
+    function ReadMachOHeader(aStream : TStream) : boolean;
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Load(aResources : TResources; aStream : TStream); override;
+    function CheckMagic(aStream : TStream) : boolean; override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    property MachineType : TMachOMachineType read fMachineType;
+  end;
+
+implementation
+
+uses machoconsts, resfactory, resourcetree, resdatastream, fpcrestypes;
+
+type
+
+  { TAbstractMachOSubReader }
+
+  TAbstractMachOSubReader = class
+  private
+  protected
+    fHeader : TMachHdr;
+    fOppositeEndianess : boolean;
+    fSegType : longword;
+    fRoot : TRootResTreeNode;
+    fParent : TMachOResourceReader;
+    function ReadString(aStream : TStream; aPos : longword) : string;
+    procedure ReadNode(aStream : TStream; aParent : TResourceTreeNode;
+      aResources : TResources; named : boolean); virtual; abstract;
+    procedure ReadResData(aStream : TStream; aNode : TResourceTreeNode;
+      aResources : TResources; datasize : longword);
+    procedure LoadResources(aResources : TResources; aStream : TStream);
+    procedure Load(aResources : TResources; aStream : TStream); virtual; abstract;
+  public
+    constructor Create(aParent : TMachOResourceReader; const aHeader : TMachHdr;
+      const aOppositeEndianess : boolean); virtual;
+    destructor Destroy; override;
+  end;
+  
+(*
+Almost all differences in 32 and 64 bit mach-o files lie in record sizes.
+Generics don't work with record types, so use macros to do this task
+(uglier, but should be the same)
+*)
+
+{$MACRO ON}
+
+//Define TMachO32SubReader
+
+{$DEFINE _TMachOSubReader_:=TMachO32SubReader}
+{$DEFINE _TSection_:=TSection32}
+{$DEFINE _TResHdr_:=TResHdr32}
+{$DEFINE _TResInfoNode_:=TResInfoNode32}
+{$DEFINE _TSegmentCommand_:=TSegmentCommand32}
+{$INCLUDE machosubreader.inc}
+
+//Define TMachO64SubReader
+
+{$DEFINE _TMachOSubReader_:=TMachO64SubReader}
+{$DEFINE _TSection_:=TSection64}
+{$DEFINE _TResHdr_:=TResHdr64}
+{$DEFINE _TResInfoNode_:=TResInfoNode64}
+{$DEFINE _TSegmentCommand_:=TSegmentCommand64}
+{$INCLUDE machosubreader.inc}
+
+//Clean all this stuff...
+{$UNDEF _TMachOSubReader_}
+{$UNDEF _TSection_}
+{$UNDEF _TResHdr_}
+{$UNDEF _TResInfoNode_}
+{$UNDEF _TSegmentCommand_}
+
+{ TAbstractMachOSubReader }
+
+function TAbstractMachOSubReader.ReadString(aStream: TStream; aPos: longword
+  ): string;
+var oldpos : int64;
+    c : char;
+    maxleft : int64;
+begin
+  Result:='';
+  oldpos:=aStream.Position;
+  aStream.Position:=aPos;
+  aStream.ReadBuffer(c,1);
+  maxleft:=aStream.Size-aStream.Position;
+  while (c<>#0) and (maxleft>=0) do
+  begin
+    Result:=Result+c;
+    aStream.ReadBuffer(c,1);
+    dec(maxleft);
+  end;
+  aStream.Position:=oldpos;
+end;
+
+procedure TAbstractMachOSubReader.ReadResData(aStream: TStream;
+  aNode: TResourceTreeNode; aResources: TResources; datasize: longword);
+var aRes : TAbstractResource;
+    RawData : TResourceDataStream;
+begin
+  aRes:=aNode.CreateResource;
+  if aRes=nil then
+    raise EResourceDuplicateException.CreateFmt(SResDuplicate,[
+      aNode.Data._Type.Name,aNode.Data.Name.Name,aNode.Data.LangID]);
+  fParent.SetDataSize(aRes,datasize);
+  fParent.SetDataOffset(aRes,aStream.Position);
+  RawData:=TResourceDataStream.Create(aStream,aRes,aRes.DataSize,TCachedResourceDataStream);
+  fParent.SetRawData(aRes,RawData);
+  fParent.AddNoTree(aResources,aRes);
+end;
+
+procedure TAbstractMachOSubReader.LoadResources(aResources: TResources;
+  aStream: TStream);
+begin
+  fRoot:=TRootResTreeNode(fParent.GetTree(aResources));
+  ReadNode(aStream,nil,aResources,false);
+end;
+
+constructor TAbstractMachOSubReader.Create(aParent: TMachOResourceReader;
+  const aHeader: TMachHdr; const aOppositeEndianess: boolean);
+begin
+  fParent:=aParent;
+  fHeader:=aHeader;
+  fOppositeEndianess:=aOppositeEndianess;
+  fRoot:=nil;
+end;
+
+destructor TAbstractMachOSubReader.Destroy;
+begin
+
+end;
+
+{ TMachOResourceReader }
+
+procedure TMachOResourceReader.SetDefaultTarget;
+begin
+  {$INCLUDE machodefaulttarget.inc}
+end;
+
+function TMachOResourceReader.ReadMachOHeader(aStream: TStream): boolean;
+var tmp : longword;
+begin
+  Result:=false;
+
+  try
+    aStream.ReadBuffer(fHeader,sizeof(fHeader));
+  except
+    on e : EReadError do exit;
+  end;
+
+  case fHeader.magic of
+    MH_MAGIC    : begin fBits:=MACH_32BIT; fOppositeEndianess:=false; end;
+    MH_MAGIC_64 : begin fBits:=MACH_64BIT; fOppositeEndianess:=false; end;
+    MH_CIGAM    : begin fBits:=MACH_32BIT; fOppositeEndianess:=true; end;
+    MH_CIGAM_64 : begin fBits:=MACH_64BIT; fOppositeEndianess:=true; end
+    else exit;
+  end;
+  
+  if fOppositeEndianess then
+    case fNativeEndianess of
+      MACH_BIG_ENDIAN    : fEndianess:=MACH_LITTLE_ENDIAN;
+      MACH_LITTLE_ENDIAN : fEndianess:=MACH_BIG_ENDIAN;
+    end
+  else fEndianess:=fNativeEndianess;
+  
+  if fOppositeEndianess then
+  begin
+    fHeader.magic:=SwapEndian(fHeader.magic);
+    fHeader.cputype:=SwapEndian(fHeader.cputype);
+    fHeader.cpusubtype:=SwapEndian(fHeader.cpusubtype);
+    fHeader.filetype:=SwapEndian(fHeader.filetype);
+    fHeader.ncmds:=SwapEndian(fHeader.ncmds);
+    fHeader.sizeofcmds:=SwapEndian(fHeader.sizeofcmds);
+    fHeader.flags:=SwapEndian(fHeader.flags);
+  end;
+  
+  case fHeader.cputype of
+    CPU_TYPE_I386      : fMachineType:=mmti386;
+    CPU_TYPE_X86_64    : fMachineType:=mmtx86_64;
+    CPU_TYPE_POWERPC   : fMachineType:=mmtpowerpc;
+    CPU_TYPE_POWERPC64 : fMachineType:=mmtpowerpc64
+    else exit;
+  end;
+  
+  //64-bit mach-o files have 4 bytes of padding after the header
+  if fBits=MACH_64BIT then
+    try
+      aStream.ReadBuffer(tmp,sizeof(tmp));
+    except
+      on e : EReadError do exit;
+    end;
+
+  Result:=true;
+end;
+
+function TMachOResourceReader.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TMachOResourceReader.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TMachOResourceReader.Load(aResources: TResources; aStream: TStream);
+var subreader : TAbstractMachOSubReader;
+begin
+  if not ReadMachOHeader(aStream) then
+    raise EResourceReaderWrongFormatException.Create('');
+    
+  case fBits of
+    MACH_32BIT : subreader:=TMachO32SubReader.Create(self,fHeader,fOppositeEndianess);
+    MACH_64BIT : subreader:=TMachO64SubReader.Create(self,fHeader,fOppositeEndianess);
+  end;
+  try
+    try
+      subreader.Load(aResources,aStream);
+    except
+      on e : EReadError do
+        raise EResourceReaderUnexpectedEndOfStreamException.Create('');
+    end;
+  finally
+    subreader.Free;
+  end;
+end;
+
+function TMachOResourceReader.CheckMagic(aStream: TStream): boolean;
+begin
+  Result:=ReadMachOHeader(aStream);
+end;
+
+constructor TMachOResourceReader.Create;
+begin
+  fExtensions:='.o .or';
+  fDescription:='Mach-O resource reader';
+  SetDefaultTarget;
+end;
+
+destructor TMachOResourceReader.Destroy;
+begin
+
+end;
+
+initialization
+  TResources.RegisterReader('.o',TMachOResourceReader);
+  TResources.RegisterReader('.or',TMachOResourceReader);
+  TResources.RegisterReader('',TMachOResourceReader);
+
+end.

+ 160 - 0
packages/fcl-res/src/machosubreader.inc

@@ -0,0 +1,160 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for Mach-O files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+type
+
+  { _TMachOSubReader_ }
+
+  _TMachOSubReader_ = class(TAbstractMachOSubReader)
+  private
+    fSection : _TSection_;
+    fResHdr : _TResHdr_;
+    procedure ReadNode(aStream : TStream; aParent : TResourceTreeNode;
+      aResources : TResources; named : boolean); override;
+    function FindResSection(aStream : TStream) : boolean;
+    procedure ReadResHeader(aStream : TStream);
+  protected
+    procedure Load(aResources : TResources; aStream : TStream); override;
+  public
+    constructor Create(aParent : TMachOResourceReader; const aHeader : TMachHdr;
+      const aOppositeEndianess : boolean); override;
+  end;
+
+{ _TMachOSubReader_ }
+
+procedure _TMachOSubReader_.ReadNode(aStream: TStream;
+  aParent: TResourceTreeNode; aResources: TResources; named: boolean);
+var infonode : _TResInfoNode_;
+    aNode : TResourceTreeNode;
+    i : integer;
+    oldpos : int64;
+    desc : TResourceDesc;
+begin
+  aStream.ReadBuffer(infonode,sizeof(infonode));
+  oldpos:=aStream.Position;
+  if fOppositeEndianess then
+  begin
+    infonode.nameid:=SwapEndian(infonode.nameid);
+    infonode.ncount:=SwapEndian(infonode.ncount);
+    infonode.idcountsize:=SwapEndian(infonode.idcountsize);
+    infonode.subptr:=SwapEndian(infonode.subptr);
+  end;
+  if aParent=nil then aNode:=fRoot
+  else
+  begin
+    desc:=TResourceDesc.Create;
+    try
+      if named then desc.Name:=ReadString(aStream,
+        fSection.offset+infonode.nameid-fSection.addr)
+      else desc.ID:=infonode.nameid;
+      aNode:=aParent.CreateSubNode(desc);
+    finally
+      desc.Free;
+    end;
+  end;
+  aStream.Position:=fSection.offset+infonode.subptr-fSection.addr;
+  if aNode.IsLeaf then
+    ReadResData(aStream,aNode,aResources,infonode.idcountsize)
+  else
+  begin
+    for i:=1 to infonode.ncount do
+      ReadNode(aStream,aNode,aResources,true);
+    for i:=1 to infonode.idcountsize do
+      ReadNode(aStream,aNode,aResources,false);
+  end;
+  aStream.Position:=oldpos;
+end;
+
+function _TMachOSubReader_.FindResSection(aStream: TStream) : boolean;
+var i,j : integer;
+    lc : TLoadCommand;
+    seg : _TSegmentCommand_;
+    nextpos : int64;
+begin
+  for i:=1 to fHeader.ncmds do
+  begin
+    aStream.ReadBuffer(lc,sizeof(lc));
+    if fOppositeEndianess then
+    begin
+      lc.cmd:=SwapEndian(lc.cmd);
+      lc.cmdsize:=SwapEndian(lc.cmdsize);
+    end;
+    nextpos:=aStream.Position-sizeof(lc)+lc.cmdsize;
+    if lc.cmdsize=0 then break;
+    if lc.cmd=fSegType then
+    begin
+      aStream.ReadBuffer(seg,sizeof(seg));
+      if fOppositeEndianess then
+        seg.nsects:=SwapEndian(seg.nsects);
+      for j:=1 to seg.nsects do
+      begin
+        aStream.ReadBuffer(fSection,sizeof(fSection));
+        if (fSection.segname=DataSegName) and (fSection.sectname=RsrcSectName) then
+        begin
+          if fOppositeEndianess then
+          begin
+            fSection.addr:=SwapEndian(fSection.addr);
+            fSection.size:=SwapEndian(fSection.size);
+            fSection.offset:=SwapEndian(fSection.offset);
+            fSection.align:=SwapEndian(fSection.align);
+            fSection.reloff:=SwapEndian(fSection.reloff);
+            fSection.nreloc:=SwapEndian(fSection.nreloc);
+            fSection.flags:=SwapEndian(fSection.flags);
+            fSection.reserved1:=SwapEndian(fSection.reserved1);
+            fSection.reserved2:=SwapEndian(fSection.reserved2);
+          end;
+          Result:=true;
+          exit;
+        end;
+      end;
+    end;
+    aStream.Position:=nextpos;
+  end;
+  //nothing found
+  Result:=false;
+  FillByte(fSection,sizeof(fSection),0);
+end;
+
+procedure _TMachOSubReader_.ReadResHeader(aStream: TStream);
+begin
+  aStream.Position:=fSection.offset;
+  aStream.ReadBuffer(fResHdr,sizeof(fResHdr));
+  if fOppositeEndianess then
+  begin
+    fResHdr.rootptr:=SwapEndian(fResHdr.rootptr);
+    fResHdr.count:=SwapEndian(fResHdr.count);
+  end;
+  aStream.Position:=fSection.offset+fResHdr.rootptr-fSection.addr;
+end;
+
+procedure _TMachOSubReader_.Load(aResources: TResources; aStream: TStream);
+begin
+  if not FindResSection(aStream) then exit;
+  ReadResHeader(aStream);
+  if fResHdr.count=0 then exit; //no resources in this file
+  LoadResources(aResources,aStream);
+end;
+
+constructor _TMachOSubReader_.Create(aParent : TMachOResourceReader;
+  const aHeader : TMachHdr; const aOppositeEndianess : boolean);
+begin
+  inherited Create(aParent,aHeader,aOppositeEndianess);
+  {$IF _TMachOSubReader_=TMachO32SubReader}
+  fSegType:=LC_SEGMENT;
+  {$ELSE}
+  fSegType:=LC_SEGMENT_64;
+  {$ENDIF}
+end;
+

+ 354 - 0
packages/fcl-res/src/machosubwriter.inc

@@ -0,0 +1,354 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource writer for Mach-O files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+type
+  _TMachOSymbolTable_ = class(TMachOSymbolTable)
+  protected
+    function AddSymbol(aName : string; sect : byte; addr : longword;
+      glob : boolean) : integer; override;
+  protected
+  public
+    procedure WriteToStream(aStream : TStream); override;
+  end;
+
+  _TMachOSubWriter_ = class(TAbstractMachOSubWriter)
+  private
+    procedure SwapSection(var aSection: _TSection_);
+  protected
+    procedure PrescanResourceTree; override;
+    procedure WriteResHeader(aStream : TStream; aResources : TResources); override;
+    procedure WriteNodeInfos(aStream : TStream); override;
+    procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); override;
+    procedure AllocateSpaceForLoadCommands(aStream : TStream); override;
+
+    procedure FixLoadCommands(aStream : TStream; aResources : TResources); override;
+    procedure FixResHeader(aStream : TStream); override;
+  public
+    constructor Create(aParent : TMachOResourceWriter; const aMachineType
+      : TMachOMachineType; const aOppositeEndianess : boolean); override;
+  end;
+
+{ _TMachOSymbolTable_ }
+
+function _TMachOSymbolTable_.AddSymbol(aName: string; sect: byte; addr: longword;
+  glob: boolean): integer;
+var p : _PNlist_;
+begin
+  p:=GetMem(sizeof(_TNlist_));
+  p^.strx:=fStringTable.Add(aName);
+  p^._type:=N_SECT;
+  if glob then p^._type:=p^._type or N_EXT;
+  p^.desc:=0;
+  p^.sect:=sect;
+  p^.value:=addr;
+  Result:=fList.Count;
+  fList.Add(p);
+end;
+
+procedure _TMachOSymbolTable_.WriteToStream(aStream: TStream);
+var nlist : _TNlist_;
+    i : integer;
+begin
+  for i:=0 to fList.Count-1 do
+  begin
+    nlist:=_PNlist_(fList[i])^;
+    if fOppositeEndianess then
+    begin
+      nlist.strx:=SwapEndian(nlist.strx);
+      nlist.desc:=SwapEndian(nlist.desc);
+      nlist.value:=SwapEndian(nlist.value);
+    end;
+    aStream.WriteBuffer(nlist,sizeof(nlist));
+  end;
+end;
+
+{ _TMachOSubWriter_ }
+
+procedure _TMachOSubWriter_.SwapSection(var aSection: _TSection_);
+begin
+  aSection.addr:=SwapEndian(aSection.addr);
+  aSection.size:=SwapEndian(aSection.size);
+  aSection.offset:=SwapEndian(aSection.offset);
+  aSection.align:=SwapEndian(aSection.align);
+  aSection.reloff:=SwapEndian(aSection.reloff);
+  aSection.nreloc:=SwapEndian(aSection.nreloc);
+  aSection.flags:=SwapEndian(aSection.flags);
+  aSection.reserved1:=SwapEndian(aSection.reserved1);
+  aSection.reserved2:=SwapEndian(aSection.reserved2);
+end;
+
+procedure _TMachOSubWriter_.PrescanResourceTree;
+begin
+  fResStrTable.Clear;
+  fRoot.SubDirRVA:=sizeof(_TResHdr_)+sizeof(_TResInfoNode_);
+  fResStrTable.StartOfs:=PrescanNode(fRoot,sizeof(_TResInfoNode_));
+  if fResStrTable.Used then
+    fDataCurOfs:=NextAligned(fDataAlignment,fResStrTable.StartOfs+fResStrTable.Size)
+  else
+    fDataCurOfs:=fResStrTable.StartOfs;
+end;
+
+procedure _TMachOSubWriter_.WriteResHeader(aStream: TStream;
+  aResources: TResources);
+var hdr : _TResHdr_;
+begin
+  hdr.rootptr:=sizeof(hdr);
+  hdr.count:=aResources.Count;
+  hdr.usedhandles:=0;
+  hdr.handles:=0;
+  fRelocations.Add(0,1);
+  fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),2);
+  if fOppositeEndianess then
+  begin
+    hdr.rootptr:=SwapEndian(hdr.rootptr);
+    hdr.count:=SwapEndian(hdr.count);
+    //handles must be fixed later
+//    hdr.usedhandles:=SwapEndian(hdr.usedhandles);
+//    hdr.handles:=SwapEndian(hdr.handles);
+  end;
+  aStream.WriteBuffer(hdr,sizeof(hdr));
+end;
+
+procedure _TMachOSubWriter_.WriteNodeInfos(aStream: TStream);
+begin
+  fCurOfs:=sizeof(_TResHdr_);
+  WriteNodeInfo(aStream,fRoot);
+  WriteSubNodes(aStream,fRoot);
+end;
+
+procedure _TMachOSubWriter_.WriteNodeInfo(aStream: TStream;
+  aNode: TResourceTreeNode);
+var infonode : _TResInfoNode_;
+begin
+  if aNode.Desc.DescType=dtID then
+    infonode.nameid:=aNode.Desc.ID
+  else
+  begin
+    infonode.nameid:=fResStrTable.StartOfs+aNode.NameRVA;
+    fRelocations.Add(fCurOfs,1);
+  end;
+  infonode.ncount:=aNode.NamedCount;
+  if aNode.IsLeaf then
+  begin
+    infonode.idcountsize:=aNode.Data.RawData.Size;
+    infonode.subptr:=fDataCurOfs;
+    fDataCurOfs:=NextAligned(fDataAlignment,fDataCurOfs+infonode.idcountsize);
+  end
+  else
+  begin
+    infonode.idcountsize:=aNode.IDCount;
+    infonode.subptr:=aNode.SubDirRVA;
+  end;
+  fRelocations.Add(
+    fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+
+    sizeof(infonode.idcountsize),1);
+  if fOppositeEndianess then
+  begin
+    infonode.nameid:=SwapEndian(infonode.nameid);
+    infonode.ncount:=SwapEndian(infonode.ncount);
+    infonode.idcountsize:=SwapEndian(infonode.idcountsize);
+    infonode.subptr:=SwapEndian(infonode.subptr);
+  end;
+  aStream.WriteBuffer(infonode,sizeof(infonode));
+  inc(fCurOfs,sizeof(infonode));
+end;
+
+procedure _TMachOSubWriter_.AllocateSpaceForLoadCommands(aStream: TStream);
+var buf : pbyte;
+begin
+  fHeader.sizeofcmds:=
+    //segment+res section+bss section
+    sizeof(_TSegmentCommand_)+sizeof(_TSection_)*2+
+    //symbol table and dynamic symbol table commands
+    sizeof(TSymtabCommand)+sizeof(TDySymtabCommand)+
+    //common header of the three commands
+    sizeof(TLoadCommand)*3;
+  buf:=GetMem(fHeader.sizeofcmds);
+  FillByte(buf^,fHeader.sizeofcmds,0);
+  try
+    aStream.WriteBuffer(buf^,fHeader.sizeofcmds);
+  finally
+    FreeMem(buf);
+  end;
+end;
+
+procedure _TMachOSubWriter_.FixLoadCommands(aStream: TStream; aResources : TResources);
+var ldcommand : TLoadCommand;
+    segcommand : _TSegmentCommand_;
+    symcommand : TSymtabCommand;
+    dysymcommand : TDySymtabCommand;
+    ressection,bsssection : _TSection_;
+begin
+  ldcommand.cmd:=fSegType;
+  ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(segcommand)+sizeof(ressection)*2;
+
+  FillByte(segcommand.name[0],16,0);
+  segcommand.vmaddr:=0;
+  segcommand.vmsize:=fDataCurOfs+sizeof(_ptrtype_)*aResources.Count;
+  segcommand.fileoff:=fSectionStart;
+  segcommand.filesize:=fDataCurOfs;
+  segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE;
+  segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE;
+  segcommand.nsects:=2;
+  segcommand.flags:=0;
+
+  ressection.sectname:=RsrcSectName;
+  ressection.segname:=DataSegName;
+  ressection.addr:=0;
+  ressection.size:=segcommand.filesize;
+  ressection.offset:=segcommand.fileoff;
+  ressection.align:=fSectAlignment;
+  ressection.reloff:=fRelocations.StartOfs;
+  ressection.nreloc:=fRelocations.Count;
+  ressection.flags:=S_ATTR_LOC_RELOC;
+  ressection.reserved1:=0;
+  ressection.reserved2:=0;
+
+  bsssection.sectname:=HandlesSectName;
+  bsssection.segname:=DataSegName;
+  bsssection.addr:=fDataCurOfs;
+  bsssection.size:=sizeof(_ptrtype_)*aResources.Count;
+  bsssection.offset:=0;
+  bsssection.align:=fSectAlignment;
+  bsssection.reloff:=0;
+  bsssection.nreloc:=0;
+  bsssection.flags:=S_ZEROFILL;
+  bsssection.reserved1:=0;
+  bsssection.reserved2:=0;
+
+  if fOppositeEndianess then
+  begin
+    ldcommand.cmd:=SwapEndian(ldcommand.cmd);
+    ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
+
+    segcommand.vmaddr:=SwapEndian(segcommand.vmaddr);
+    segcommand.vmsize:=SwapEndian(segcommand.vmsize);
+    segcommand.fileoff:=SwapEndian(segcommand.fileoff);
+    segcommand.filesize:=SwapEndian(segcommand.filesize);
+    segcommand.maxprot:=SwapEndian(segcommand.maxprot);
+    segcommand.initprot:=SwapEndian(segcommand.initprot);
+    segcommand.nsects:=SwapEndian(segcommand.nsects);
+    segcommand.flags:=SwapEndian(segcommand.flags);
+
+    SwapSection(ressection);
+    SwapSection(bsssection);
+  end;
+
+  aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
+  aStream.WriteBuffer(segcommand,sizeof(segcommand));
+  aStream.WriteBuffer(ressection,sizeof(ressection));
+  aStream.WriteBuffer(bsssection,sizeof(bsssection));
+
+  ldcommand.cmd:=LC_SYMTAB;
+  ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(symcommand);
+
+  symcommand.symoff:=fSymbolTable.StartOfs;
+  symcommand.nsyms:=fSymbolTable.Count;
+  symcommand.stroff:=fMachOStringTable.StartOfs;
+  symcommand.strsize:=NextAligned(fDataAlignment,fMachOStringTable.Size);
+
+  if fOppositeEndianess then
+  begin
+    ldcommand.cmd:=SwapEndian(ldcommand.cmd);
+    ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
+
+    symcommand.symoff:=SwapEndian(symcommand.symoff);
+    symcommand.nsyms:=SwapEndian(symcommand.nsyms);
+    symcommand.stroff:=SwapEndian(symcommand.stroff);
+    symcommand.strsize:=SwapEndian(symcommand.strsize);
+  end;
+
+  aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
+  aStream.WriteBuffer(symcommand,sizeof(symcommand));
+
+  ldcommand.cmd:=LC_DYSYMTAB;
+  ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(dysymcommand);
+
+  dysymcommand.ilocalsym:=0;
+  dysymcommand.nlocalsym:=fSymbolTable.LocalCount;
+  dysymcommand.iextdefsym:=dysymcommand.ilocalsym+dysymcommand.nlocalsym;
+  dysymcommand.nextdefsym:=fSymbolTable.GlobalCount;
+  dysymcommand.iundefsym:=dysymcommand.iextdefsym+dysymcommand.nextdefsym;
+  dysymcommand.nundefsym:=0;
+  dysymcommand.tocoff:=0;
+  dysymcommand.ntoc:=0;
+  dysymcommand.modtaboff:=0;
+  dysymcommand.nmodtab:=0;
+  dysymcommand.extrefsymoff:=0;
+  dysymcommand.nextrefsyms:=0;
+  dysymcommand.indirectsymoff:=0;
+  dysymcommand.nindirectsyms:=0;
+  dysymcommand.extreloff:=0;
+  dysymcommand.nextrel:=0;
+  dysymcommand.locreloff:=0;
+  dysymcommand.nlocrel:=0;
+
+  if fOppositeEndianess then
+  begin
+    ldcommand.cmd:=SwapEndian(ldcommand.cmd);
+    ldcommand.cmdsize:=SwapEndian(ldcommand.cmdsize);
+
+    dysymcommand.ilocalsym:=SwapEndian(dysymcommand.ilocalsym);
+    dysymcommand.nlocalsym:=SwapEndian(dysymcommand.nlocalsym);
+    dysymcommand.iextdefsym:=SwapEndian(dysymcommand.iextdefsym);
+    dysymcommand.nextdefsym:=SwapEndian(dysymcommand.nextdefsym);
+    dysymcommand.iundefsym:=SwapEndian(dysymcommand.iundefsym);
+    dysymcommand.nundefsym:=SwapEndian(dysymcommand.nundefsym);
+    dysymcommand.tocoff:=SwapEndian(dysymcommand.tocoff);
+    dysymcommand.ntoc:=SwapEndian(dysymcommand.ntoc);
+    dysymcommand.modtaboff:=SwapEndian(dysymcommand.modtaboff);
+    dysymcommand.nmodtab:=SwapEndian(dysymcommand.nmodtab);
+    dysymcommand.extrefsymoff:=SwapEndian(dysymcommand.extrefsymoff);
+    dysymcommand.nextrefsyms:=SwapEndian(dysymcommand.nextrefsyms);
+    dysymcommand.indirectsymoff:=SwapEndian(dysymcommand.indirectsymoff);
+    dysymcommand.nindirectsyms:=SwapEndian(dysymcommand.nindirectsyms);
+    dysymcommand.extreloff:=SwapEndian(dysymcommand.extreloff);
+    dysymcommand.nextrel:=SwapEndian(dysymcommand.nextrel);
+    dysymcommand.locreloff:=SwapEndian(dysymcommand.locreloff);
+    dysymcommand.nlocrel:=SwapEndian(dysymcommand.nlocrel);
+  end;
+
+  aStream.WriteBuffer(ldcommand,sizeof(ldcommand));
+  aStream.WriteBuffer(dysymcommand,sizeof(dysymcommand));
+end;
+
+procedure _TMachOSubWriter_.FixResHeader(aStream : TStream);
+var hdr : _TResHdr_;
+begin
+  hdr.handles:=fDataCurOfs;
+  if fOppositeEndianess then
+    hdr.handles:=SwapEndian(hdr.handles);
+  aStream.Seek(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),
+    soFromCurrent);
+  aStream.WriteBuffer(hdr.handles,sizeof(hdr.handles));
+end;
+
+constructor _TMachOSubWriter_.Create(aParent : TMachOResourceWriter;
+  const aMachineType : TMachOMachineType; const aOppositeEndianess : boolean);
+begin
+  inherited Create(aParent, aMachineType,aOppositeEndianess);
+  fSymbolTable:=_TMachOSymbolTable_.Create(fMachOStringTable);
+  fSymbolTable.OppositeEndianess:=fOppositeEndianess;
+  {$IF _TMachOSubWriter_=TMachO32SubWriter}
+  fDataAlignment:=4;
+  fSectAlignment:=2; //2^2
+  fSegType:=LC_SEGMENT;
+  {$ELSE}
+  fDataAlignment:=8;
+  fSectAlignment:=3; //2^3
+  fSegType:=LC_SEGMENT_64;
+  {$ENDIF}
+end;
+

+ 151 - 0
packages/fcl-res/src/machotypes.pp

@@ -0,0 +1,151 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Types used by Mach-O resource reader and writer
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit machotypes;
+
+{$MODE OBJFPC}
+
+interface
+
+type
+  TMachOMachineType = (mmtpowerpc, mmtpowerpc64, mmti386, mmtx86_64);
+  TSegSectName = array[0..15] of char;
+
+type
+  TMachHdr = packed record
+    magic : longword;
+    cputype : longint;
+    cpusubtype : longint;
+    filetype : longword;
+    ncmds : longword;
+    sizeofcmds : longword;
+    flags : longword;
+  end;
+
+  TLoadCommand = packed record
+    cmd : longword;
+    cmdsize : longword;
+  end;
+
+  //note: all commands don't include first two longwords
+
+  TSegmentCommand32 = packed record
+    name     : TSegSectName;
+    vmaddr   : longword;
+    vmsize   : longword;
+    fileoff  : longword;
+    filesize : longword;
+    maxprot  : longint;
+    initprot : longint;
+    nsects   : longword;
+    flags    : longword;
+  end;
+
+  TSegmentCommand64 = packed record
+    name     : TSegSectName;
+    vmaddr   : qword;
+    vmsize   : qword;
+    fileoff  : qword;
+    filesize : qword;
+    maxprot  : longint;
+    initprot : longint;
+    nsects   : longword;
+    flags    : longword;
+  end;
+  
+  TSection32 = packed record
+    sectname : TSegSectName;
+    segname  : TSegSectName;
+    addr : longword;
+    size : longword;
+    offset : longword;
+    align : longword;
+    reloff : longword;
+    nreloc : longword;
+    flags : longword;
+    reserved1 : longword;
+    reserved2 : longword;
+  end;
+
+  TSection64 = packed record
+    sectname : TSegSectName;
+    segname  : TSegSectName;
+    addr : qword;
+    size : qword;
+    offset : longword;
+    align : longword;
+    reloff : longword;
+    nreloc : longword;
+    flags : longword;
+    reserved1 : longword;
+    reserved2 : longword;
+    reserved3 : longword;
+  end;
+
+  TSymtabCommand = packed record
+    symoff : longword;
+    nsyms : longword;
+    stroff : longword;
+    strsize : longword;
+  end;
+  
+  TDySymtabCommand = packed record
+    ilocalsym : longword;
+    nlocalsym : longword;
+    iextdefsym : longword;
+    nextdefsym : longword;
+    iundefsym : longword;
+    nundefsym : longword;
+    tocoff : longword;
+    ntoc : longword;
+    modtaboff : longword;
+    nmodtab : longword;
+    extrefsymoff : longword;
+    nextrefsyms : longword;
+    indirectsymoff : longword;
+    nindirectsyms : longword;
+    extreloff : longword;
+    nextrel : longword;
+    locreloff : longword;
+    nlocrel : longword;
+  end;
+  
+  TNList32 = packed record
+    strx : longword;
+    _type : byte;
+    sect : byte;
+    desc : word;
+    value : longword;
+  end;
+  PNList32 = ^TNList32;
+  
+  TNList64 = packed record
+    strx : longword;
+    _type : byte;
+    sect : byte;
+    desc : word;
+    value : qword;
+  end;
+  PNList64 = ^TNList64;
+
+  TRelocationInfo = packed record
+    address : longword;
+    flags : longword;
+  end;
+  PRelocationInfo = ^TRelocationInfo;
+
+implementation
+
+end.

+ 618 - 0
packages/fcl-res/src/machowriter.pp

@@ -0,0 +1,618 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource writer for Mach-O files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit machowriter;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, machotypes;
+
+type
+  EMachOResourceWriterException = class(EResourceWriterException);
+  EMachOResourceWriterUnknownBitSizeException = class(EMachOResourceWriterException);
+
+type
+
+  { TMachOResourceWriter }
+
+  TMachOResourceWriter = class(TAbstractResourceWriter)
+  private
+    fExtensions : string;
+    fDescription : string;
+    fNativeEndianess : integer;
+    fEndianess : integer;
+    fOppositeEndianess : boolean;
+    fMachineType : TMachOMachineType;
+    fBits : integer;
+
+    procedure SetDefaultTarget;
+    procedure SetMachineType(const aMachineType : TMachOMachineType);
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Write(aResources : TResources; aStream : TStream); override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+    property MachineType : TMachOMachineType read fMachineType write SetMachineType;
+  end;
+
+implementation
+
+uses resourcetree, machoconsts, strtable, fpcrestypes;
+
+type
+
+  { TMachORelocations }
+
+  TMachORelocations = class
+  private
+    fList : TFPList;
+    fStartOfs : longword;
+    fOppositeEndianess : boolean;
+    fEndianess : integer;
+    fRelocType : longword;
+    fRelocSize : longword;
+    function GetCount : integer;
+  protected
+  public
+    constructor Create(aMachineType : TMachOMachineType; aOppositeEndianess : boolean);
+    destructor Destroy; override;
+    procedure Add(addr : longword; sectnum : longword);
+    procedure Clear;
+    procedure WriteToStream(aStream : TStream);
+    property Count : integer read GetCount;
+    property StartOfs : longword read fStartOfs write fStartOfs;
+  end;
+
+  { TMachOSymbolTable }
+
+  TMachOSymbolTable = class
+  protected
+    fStringTable : TObjectStringTable;
+    fList : TFPList;
+    fStartOfs : longword;
+    fLocalCount : integer;
+    fGlobalCount : integer;
+    fOppositeEndianess : boolean;
+    function GetCount : integer;
+    function AddSymbol(aName : string; sect : byte; addr : longword;
+      glob : boolean) : integer; virtual; abstract;
+  protected
+  public
+    constructor Create(aStringTable : TObjectStringTable);
+    destructor Destroy; override;
+    function AddLocal(aName : string; sect : byte; addr : longword) : integer;
+    function AddGlobal(aName : string; sect : byte; addr : longword) : integer;
+    procedure Clear;
+    procedure WriteToStream(aStream : TStream); virtual; abstract;
+    property Count : integer read GetCount;
+    property LocalCount : integer read fLocalCount;
+    property GlobalCount : integer read fGlobalCount;
+    property StartOfs : longword read fStartOfs write fStartOfs;
+    property OppositeEndianess : boolean read fOppositeEndianess write fOppositeEndianess;
+  end;
+
+  { TAbstractMachOSubWriter }
+
+  TAbstractMachOSubWriter = class
+  protected
+    fParent : TMachOResourceWriter;
+    fOppositeEndianess : boolean;
+    fMachineType : TMachOMachineType;
+    fDataAlignment : integer;
+    fSectAlignment : integer;
+    fSegType : longword;
+    fHeader : TMachHdr;
+    fMachOStringTable : TObjectStringTable;
+    fSymbolTable : TMachOSymbolTable;
+    fRelocations : TMachORelocations;
+    fRoot : TRootResTreeNode;
+    fResStrTable : TResStringTable;
+    fCurOfs : longword;
+    fDataCurOfs : longword;
+    fSectionStart : longword;
+
+    function NextAligned(aBound, aValue : longword) : longword;
+    procedure Align(aBound : integer; aStream : TStream);
+
+    procedure PrescanResourceTree; virtual; abstract;
+    function PrescanNode(aNode : TResourceTreeNode; aNodeSize : longword) : longword;
+
+    procedure WriteEmptyMachOHeader(aStream : TStream);
+    procedure WriteResHeader(aStream : TStream; aResources : TResources); virtual; abstract;
+    procedure WriteNodeInfos(aStream : TStream); virtual; abstract;
+    procedure WriteNodeInfo(aStream : TStream; aNode : TResourceTreeNode); virtual; abstract;
+    procedure WriteSubNodes(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteResStringTable(aStream : TStream);
+    procedure WriteRawData(aStream : TStream);
+    procedure WriteResData(aStream : TStream; aNode : TResourceTreeNode);
+    procedure WriteRelocations(aStream : TStream);
+    procedure WriteSymbolTable(aStream : TStream);
+    procedure WriteMachOStringTable(aStream : TStream);
+    procedure AllocateSpaceForLoadCommands(aStream : TStream); virtual; abstract;
+
+    procedure FixHeader(aStream : TStream);
+    procedure FixLoadCommands(aStream : TStream; aResources : TResources); virtual; abstract;
+    procedure FixResHeader(aStream : TStream); virtual; abstract;
+
+    procedure Write(aResources: TResources; aStream: TStream);
+  public
+    constructor Create(aParent : TMachOResourceWriter; const aMachineType
+      : TMachOMachineType; const aOppositeEndianess : boolean); virtual;
+    destructor Destroy; override;
+  end;
+
+(*
+Almost all differences in 32 and 64 bit mach-o files lie in record sizes.
+Generics don't work with record types, so use macros to do this task
+(uglier, but should be the same)
+*)
+
+{$MACRO ON}
+
+//Define TMachO32SymbolTable and TMachO32SubWriter
+
+{$DEFINE _TMachOSymbolTable_:=TMachO32SymbolTable}
+{$DEFINE _TMachOSubWriter_:=TMachO32SubWriter}
+{$DEFINE _TNlist_:=TNlist32}
+{$DEFINE _PNList_:=PNList32}
+{$DEFINE _TResHdr_:=TResHdr32}
+{$DEFINE _TResInfoNode_:=TResInfoNode32}
+{$DEFINE _TSegmentCommand_:=TSegmentCommand32}
+{$DEFINE _TSection_:=TSection32}
+{$DEFINE _ptrtype_:=longword}
+{$INCLUDE machosubwriter.inc}
+
+//Define TMachO64SymbolTable and TMachO64SubWriter
+
+{$DEFINE _TMachOSymbolTable_:=TMachO64SymbolTable}
+{$DEFINE _TMachOSubWriter_:=TMachO64SubWriter}
+{$DEFINE _TNlist_:=TNlist64}
+{$DEFINE _PNList_:=PNList64}
+{$DEFINE _TResHdr_:=TResHdr64}
+{$DEFINE _TResInfoNode_:=TResInfoNode64}
+{$DEFINE _TSegmentCommand_:=TSegmentCommand64}
+{$DEFINE _TSection_:=TSection64}
+{$DEFINE _ptrtype_:=qword}
+{$INCLUDE machosubwriter.inc}
+
+//Clean all this stuff...
+
+{$UNDEF _TMachOSymbolTable_}
+{$UNDEF _TMachOSubWriter_}
+{$UNDEF _TNlist_}
+{$UNDEF _PNList_}
+{$UNDEF _TResHdr_}
+{$UNDEF _TResInfoNode_}
+{$UNDEF _TSegmentCommand_}
+{$UNDEF _TSection_}
+
+{ TMachOSymbolTable }
+
+function TMachOSymbolTable.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+constructor TMachOSymbolTable.Create(aStringTable: TObjectStringTable);
+begin
+  fStringTable:=aStringTable;
+  fList:=TFPList.Create;
+  fStartOfs:=0;
+  fLocalCount:=0;
+  fGlobalCount:=0;
+  fOppositeEndianess:=false;
+end;
+
+destructor TMachOSymbolTable.Destroy;
+begin
+  Clear;
+  fList.Free;
+end;
+
+function TMachOSymbolTable.AddLocal(aName: string; sect: byte; addr: longword
+  ): integer;
+begin
+  Result:=AddSymbol(aName,sect,addr,false);
+  inc(fLocalCount);
+end;
+
+function TMachOSymbolTable.AddGlobal(aName: string; sect: byte; addr: longword
+  ): integer;
+begin
+  Result:=AddSymbol(aName,sect,addr,true);
+  inc(fGlobalCount);
+end;
+
+procedure TMachOSymbolTable.Clear;
+var i : integer;
+begin
+  for i:=0 to fList.Count-1 do
+    FreeMem(fList[i]);
+  fList.Clear;
+end;
+
+{ TMachORelocations }
+
+function TMachORelocations.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+constructor TMachORelocations.Create(aMachineType : TMachOMachineType;
+  aOppositeEndianess : boolean);
+begin
+  fList:=TFPList.Create;
+  fStartOfs:=0;
+
+  case aMachineType of
+    mmtpowerpc   : begin
+                     fEndianess:=MACH_BIG_ENDIAN;
+                     fRelocType:=PPC_RELOC_VANILLA;
+                     fRelocSize:=2;
+                   end;
+    mmtpowerpc64 : begin
+                     fEndianess:=MACH_BIG_ENDIAN;
+                     fRelocType:=PPC_RELOC_VANILLA;
+                     fRelocSize:=3;
+                   end;
+    mmti386      : begin
+                     fEndianess:=MACH_LITTLE_ENDIAN;
+                     fRelocType:=GENERIC_RELOC_VANILLA;
+                     fRelocSize:=2;
+                   end;
+    mmtx86_64    : begin
+                     fEndianess:=MACH_LITTLE_ENDIAN;
+                     fRelocType:=X86_64_RELOC_UNSIGNED;
+                     fRelocSize:=3;
+                   end;
+  end;
+  fOppositeEndianess:=aOppositeEndianess;
+end;
+
+destructor TMachORelocations.Destroy;
+begin
+  Clear;
+  fList.Free;
+end;
+
+procedure TMachORelocations.Add(addr: longword; sectnum: longword);
+var p : PRelocationInfo;
+begin
+  p:=GetMem(sizeof(TRelocationInfo));
+  p^.address:=addr;
+  //bit fields make things difficult...
+  if fEndianess=MACH_BIG_ENDIAN then
+  begin
+    p^.flags:=sectnum shl 8;
+    p^.flags:=p^.flags or (fRelocSize shl 5); //length
+    p^.flags:=p^.flags or fRelocType;
+  end
+  else
+  begin
+    p^.flags:=sectnum and R_SYMBOLNUM_LE;
+    p^.flags:=p^.flags or (fRelocSize shl 25); //length
+    p^.flags:=p^.flags or (fRelocType shl 28);
+  end;
+  fList.Add(p);
+end;
+
+procedure TMachORelocations.Clear;
+var i : integer;
+begin
+  for i:=0 to fList.Count-1 do
+    FreeMem(PRelocationInfo(fList[i]));
+  fList.Clear;
+end;
+
+procedure TMachORelocations.WriteToStream(aStream: TStream);
+var rel : TRelocationInfo;
+    i : integer;
+begin
+  for i:=0 to fList.Count-1 do
+  begin
+    rel:=PRelocationInfo(fList[i])^;
+    if fOppositeEndianess then
+    begin
+      rel.address:=SwapEndian(rel.address);
+      rel.flags:=SwapEndian(rel.flags);
+    end;
+    aStream.WriteBuffer(rel,sizeof(rel));
+  end;
+end;
+
+{ TAbstractMachOSubWriter }
+
+function TAbstractMachOSubWriter.NextAligned(aBound, aValue: longword): longword;
+var topad : longword;
+begin
+  Result:=aValue;
+  topad:=aBound-(aValue mod aBound);
+  if topad<>aBound then inc(Result,topad);
+end;
+
+procedure TAbstractMachOSubWriter.Align(aBound: integer; aStream: TStream);
+var topad,tmp : integer;
+    qw : qword;
+begin
+  qw:=0;
+  topad:=aBound-(aStream.Position mod aBound);
+  if topad<>aBound then
+    while topad>0 do
+    begin
+      if topad>8 then tmp:=8 else tmp:=topad;
+      aStream.WriteBuffer(qw,tmp);
+      dec(topad,tmp);
+    end;
+end;
+
+function TAbstractMachOSubWriter.PrescanNode(aNode: TResourceTreeNode;
+  aNodeSize : longword): longword;
+var curofs : longword;
+    i : integer;
+    subnode : TResourceTreeNode;
+begin
+  if aNode.IsLeaf then
+  begin
+    Result:=aNode.SubDirRVA;
+    exit;
+  end;
+
+  if aNode.Desc.DescType=dtName then
+    aNode.NameRVA:=fResStrTable.Add(aNode.Desc.Name);
+
+  //first node subnodes begin at curofs (after all node headers)
+  curofs:=aNode.SubDirRva+(aNode.NamedCount+aNode.IDCount)*aNodeSize;
+  for i:=0 to aNode.NamedCount-1 do
+  begin
+    subnode:=aNode.NamedEntries[i];
+    subnode.SubDirRVA:=curofs;
+    curofs:=PrescanNode(subnode,aNodeSize);
+  end;
+  for i:=0 to aNode.IDCount-1 do
+  begin
+    subnode:=aNode.IDEntries[i];
+    subnode.SubDirRVA:=curofs;
+    curofs:=PrescanNode(subnode,aNodeSize);
+  end;
+  Result:=curofs;
+end;
+
+procedure TAbstractMachOSubWriter.WriteEmptyMachOHeader(aStream: TStream);
+begin
+  FillByte(fHeader,sizeof(TMachHdr),0);
+  aStream.WriteBuffer(fHeader,sizeof(TMachHdr));
+  Align(fDataAlignment,aStream);
+end;
+
+procedure TAbstractMachOSubWriter.WriteSubNodes(aStream: TStream;
+  aNode: TResourceTreeNode);
+var i : integer;
+begin
+  for i:=0 to aNode.NamedCount-1 do
+    WriteNodeInfo(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteNodeInfo(aStream,aNode.IDEntries[i]);
+
+  for i:=0 to aNode.NamedCount-1 do
+    WriteSubNodes(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteSubNodes(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TAbstractMachOSubWriter.WriteResStringTable(aStream: TStream);
+begin
+  if fResStrTable.Used then
+    fResStrTable.WriteToStream(aStream);
+  Align(fDataAlignment,aStream);
+end;
+
+procedure TAbstractMachOSubWriter.WriteRawData(aStream: TStream);
+begin
+  WriteResData(aStream,fRoot);
+end;
+
+procedure TAbstractMachOSubWriter.WriteResData(aStream: TStream;
+  aNode: TResourceTreeNode);
+var rawdata : TStream;
+    i : integer;
+begin
+  if aNode.IsLeaf then
+  begin
+    rawdata:=aNode.Data.RawData;
+    rawdata.Position:=0;
+    aStream.CopyFrom(rawdata,rawdata.Size);
+    Align(fDataAlignment,aStream);
+    exit;
+  end;
+  for i:=0 to aNode.NamedCount-1 do
+    WriteResData(aStream,aNode.NamedEntries[i]);
+  for i:=0 to aNode.IDCount-1 do
+    WriteResData(aStream,aNode.IDEntries[i]);
+end;
+
+procedure TAbstractMachOSubWriter.WriteRelocations(aStream: TStream);
+begin
+  fRelocations.WriteToStream(aStream);
+end;
+
+procedure TAbstractMachOSubWriter.WriteSymbolTable(aStream: TStream);
+begin
+  fSymbolTable.WriteToStream(aStream);
+end;
+
+procedure TAbstractMachOSubWriter.WriteMachOStringTable(aStream: TStream);
+begin
+  fMachOStringTable.WriteToStream(aStream);
+  Align(fDataAlignment,aStream);
+end;
+
+procedure TAbstractMachOSubWriter.FixHeader(aStream: TStream);
+begin
+  aStream.Position:=0;
+  case fMachineType of
+    mmtpowerpc   : begin
+                     fHeader.magic:=MH_MAGIC;
+                     fHeader.cputype:=CPU_TYPE_POWERPC;
+                     fHeader.cpusubtype:=CPU_SUBTYPE_POWERPC_ALL;
+                   end;
+    mmtpowerpc64 : begin
+                     fHeader.magic:=MH_MAGIC_64;
+                     fHeader.cputype:=CPU_TYPE_POWERPC64;
+                     fHeader.cpusubtype:=CPU_SUBTYPE_POWERPC_ALL;
+                   end;
+    mmti386      : begin
+                     fHeader.magic:=MH_MAGIC;
+                     fHeader.cputype:=CPU_TYPE_I386;
+                     fHeader.cpusubtype:=CPU_SUBTYPE_I386_ALL;
+                   end;
+    mmtx86_64    : begin
+                     fHeader.magic:=MH_MAGIC_64;
+                     fHeader.cputype:=CPU_TYPE_X86_64;
+                     fHeader.cpusubtype:=CPU_SUBTYPE_X86_64_ALL;
+                   end;
+  end;
+  fHeader.filetype:=MH_OBJECT;
+  fHeader.ncmds:=3;
+  fHeader.flags:=0;
+  
+  if fOppositeEndianess then
+  begin
+    fHeader.magic:=SwapEndian(fHeader.magic);
+    fHeader.cputype:=SwapEndian(fHeader.cputype);
+    fHeader.cpusubtype:=SwapEndian(fHeader.cpusubtype);
+    fHeader.filetype:=SwapEndian(fHeader.filetype);
+    fHeader.ncmds:=SwapEndian(fHeader.ncmds);
+    fHeader.sizeofcmds:=SwapEndian(fHeader.sizeofcmds);
+    fHeader.flags:=SwapEndian(fHeader.flags);
+  end;
+  aStream.WriteBuffer(fHeader,sizeof(fHeader));
+  Align(fDataAlignment,aStream);
+end;
+
+procedure TAbstractMachOSubWriter.Write(aResources: TResources; aStream: TStream);
+begin
+  WriteEmptyMachOHeader(aStream);
+  AllocateSpaceForLoadCommands(aStream);
+  fSectionStart:=aStream.Position;
+  fRoot:=TRootResTreeNode(fParent.GetTree(aResources));
+  PrescanResourceTree;
+  WriteResHeader(aStream,aResources);
+  WriteNodeInfos(aStream);
+  WriteResStringTable(aStream);
+  WriteRawData(aStream);
+//  fSymbolTable.AddGlobal('FPCRES_SECTION',1,0);
+  fSymbolTable.AddGlobal('FPC_RESSYMBOL',1,0);
+  fRelocations.StartOfs:=aStream.Position;
+  WriteRelocations(aStream);
+  fSymbolTable.StartOfs:=aStream.Position;
+  WriteSymbolTable(aStream);
+  fMachOStringTable.StartOfs:=aStream.Position;
+  WriteMachOStringTable(aStream);
+  FixHeader(aStream);
+  FixLoadCommands(aStream,aResources);
+  FixResHeader(aStream);
+end;
+
+constructor TAbstractMachOSubWriter.Create(aParent : TMachOResourceWriter;
+  const aMachineType : TMachOMachineType; const aOppositeEndianess : boolean);
+begin
+  fParent:=aParent;
+  fMachineType:=aMachineType;
+  fOppositeEndianess:=aOppositeEndianess;
+  fRoot:=nil;
+  fMachOStringTable:=TObjectStringTable.Create(nil,0);
+  fRelocations:=TMachORelocations.Create(fMachineType,fOppositeEndianess);
+  fResStrTable:=TResStringTable.Create;
+  fCurOfs:=0;
+  fDataCurOfs:=0;
+  fSectionStart:=0;
+end;
+
+destructor TAbstractMachOSubWriter.Destroy;
+begin
+  fSymbolTable.Free;
+  fResStrTable.Free;
+  fRelocations.Free;
+  fMachOStringTable.Free;
+end;
+
+{ TMachOResourceWriter }
+
+procedure TMachOResourceWriter.SetDefaultTarget;
+begin
+  {$INCLUDE machodefaulttarget.inc}
+end;
+
+procedure TMachOResourceWriter.SetMachineType(
+  const aMachineType: TMachOMachineType);
+begin
+  case aMachineType of
+    mmtpowerpc   : begin fBits:=MACH_32BIT; fEndianess:=MACH_BIG_ENDIAN; end;
+    mmtpowerpc64 : begin fBits:=MACH_64BIT; fEndianess:=MACH_BIG_ENDIAN; end;
+    mmti386      : begin fBits:=MACH_32BIT; fEndianess:=MACH_LITTLE_ENDIAN; end;
+    mmtx86_64    : begin fBits:=MACH_64BIT; fEndianess:=MACH_LITTLE_ENDIAN; end;
+  end;
+  fMachineType:=aMachineType;
+  fOppositeEndianess:=fNativeEndianess<>fEndianess;
+end;
+
+function TMachOResourceWriter.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TMachOResourceWriter.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TMachOResourceWriter.Write(aResources: TResources; aStream: TStream);
+var subwriter : TAbstractMachOSubWriter;
+begin
+  case fBits of
+    MACH_32BIT : subwriter:=TMachO32SubWriter.Create(self,fMachineType,fOppositeEndianess);
+    MACH_64BIT : subwriter:=TMachO64SubWriter.Create(self,fMachineType,fOppositeEndianess)
+  else
+    raise EMachOResourceWriterUnknownBitSizeException.Create('');
+  end;
+  try
+    subwriter.Write(aResources,aStream);
+  finally
+    subwriter.Free;
+  end;
+end;
+
+constructor TMachOResourceWriter.Create;
+begin
+  fExtensions:='.o .or';
+  fDescription:='Mach-O resource writer';
+  SetDefaultTarget;
+end;
+
+destructor TMachOResourceWriter.Destroy;
+begin
+
+end;
+
+initialization
+  TResources.RegisterWriter('.o',TMachOResourceWriter);
+  TResources.RegisterWriter('.or',TMachOResourceWriter);
+
+end.

+ 332 - 0
packages/fcl-res/src/prova.pp

@@ -0,0 +1,332 @@
+{off $DEFINE PARSEDFM}
+{off $DEFINE PARSESTRINGTABLE}
+{off $DEFINE DUMPBITMAP}
+{off $DEFINE DUMPICON}
+{off $DEFINE DUMPCURSOR}
+{off $DEFINE PRINTVERSION}
+{off $DEFINE PRINTACCELERATORS}
+
+(*
+da fare:
+   
+ - ordinare le robe registrabili (reader, writer, resource types) in modo da
+   velocizzare la ricerca.
+   
+ - tipi di resource da fare:
+   menu
+   dialog
+   messagetable
+   
+*)
+
+program prova;
+
+{$mode objfpc}{$H+}
+
+{$APPTYPE CONSOLE}
+
+uses
+  Classes, SysUtils,
+  resource, resfactory,
+  stringtableresource, bitmapresource, groupiconresource, groupcursorresource,
+  versionresource, versiontypes, acceleratorsresource,
+  resreader, reswriter, coffwriter, coffreader, elfreader, elfwriter, dfmreader,
+  winpeimagereader, externalreader, externalwriter, machoreader, machowriter;
+  
+
+
+
+function MemFlagsToStr(mf : word) : string;
+begin
+  Result:='';
+  if (mf and MF_MOVEABLE) = MF_MOVEABLE then Result:=Result+' | MOVEABLE';
+  if (mf and MF_PURE) = MF_PURE then Result:=Result+' | PURE';
+  if (mf and MF_PRELOAD) = MF_PRELOAD then Result:=Result+' | PRELOAD';
+  if (mf and MF_DISCARDABLE) = MF_DISCARDABLE then Result:=Result+' | DISCARDABLE';
+  Result:=copy(Result,4,Length(Result));
+end;
+
+function ResTypeToStr(aType : TResourceDesc) : string;
+begin
+  if aType.DescType=dtName then Result:=''''+aType.Name+''''
+  else
+    case aType.ID of
+      RT_CURSOR       : Result:='CURSOR';
+      RT_BITMAP       : Result:='BITMAP';
+      RT_ICON         : Result:='ICON';
+      RT_MENU         : Result:='MENU';
+      RT_DIALOG       : Result:='DIALOG';
+      RT_STRING       : Result:='STRING';
+      RT_FONTDIR      : Result:='FONTDIR';
+      RT_FONT         : Result:='FONT';
+      RT_ACCELERATOR  : Result:='ACCELERATOR';
+      RT_RCDATA       : Result:='RCDATA';
+      RT_MESSAGETABLE : Result:='MESSAGETABLE';
+      RT_GROUP_CURSOR : Result:='GROUP_CURSOR';
+      RT_GROUP_ICON   : Result:='GROUP_ICON';
+      RT_VERSION      : Result:='VERSION';
+      RT_DLGINCLUDE   : Result:='DLGINCLUDE';
+      RT_PLUGPLAY     : Result:='PLUGPLAY';
+      RT_VXD          : Result:='VXD';
+      RT_ANICURSOR    : Result:='ANICURSOR';
+      RT_ANIICON      : Result:='ANIICON';
+      RT_HTML         : Result:='HTML';
+      RT_MANIFEST     : Result:='MANIFEST'
+      else Result:=aType.Name;
+    end;
+end;
+
+procedure PrintRow(aStream : TStream; toread : integer);
+var i,j : integer;
+    b : array[0..3] of byte;
+    s : string;
+    ascii : string;
+begin
+  s:=' ';
+  ascii:='';
+  while toread>0 do
+  begin
+    i:=4;
+    if toread<4 then i:=toread;
+    aStream.ReadBuffer(b[0],i);
+    dec(toread,i);
+    for j:=0 to i-1 do
+    begin
+      s:=s+IntToHex(b[j],2)+' ';
+      if b[j]>=$20 then ascii:=ascii+chr(b[j])
+      else ascii:=ascii+'.';
+    end;
+    s:=s+'  ';
+  end;
+  if length(s)<57 then
+  begin
+    i:=57-length(s);
+    for j:=1 to i do
+      s:=s+' ';
+  end;
+  writeln(s+'   '+ascii);
+end;
+
+procedure PrintDFM(aStream : TStream);
+var outstr : TMemoryStream;
+    sl : TStringList;
+    i : integer;
+begin
+  outstr:=TMemoryStream.Create;
+  try
+    sl:=TStringList.Create;
+    try
+      ObjectBinaryToText(aStream,outstr);
+      outstr.Position:=0;
+      sl.LoadFromStream(outstr);
+      for i:=0 to sl.Count-1 do
+        writeln(sl[i]);
+    finally
+      sl.Free;
+    end;
+  finally
+    outstr.Free;
+  end;
+end;
+
+procedure PrintStringTable(aRes : TAbstractResource);
+var strtab : TStringTableResource;
+    id : word;
+begin
+  strtab:=TStringTableResource(aRes);
+  for id:=strtab.FirstID to strtab.LastID do
+    if strtab.Strings[id]<>'' then
+      writeln(Format('%.5d = %s',[id,strtab.Strings[id]]));
+end;
+
+procedure DumpBitmap(aRes : TBitmapResource);
+var fs : TFileStream;
+begin
+  fs:=TFileStream.Create(aRes.Name.Name+'.bmp',fmCreate);
+  try
+    aRes.BitmapData.Position:=0;
+    fs.CopyFrom(aRes.BitmapData,aRes.BitmapData.Size);
+  finally
+    fs.Free;
+  end;
+end;
+
+{$IFDEF DUMPICON}
+procedure DumpIcon(aRes : TGroupIconResource);
+var fs : TFileStream;
+begin
+  fs:=TFileStream.Create(aRes.Name.Name+'.ico',fmCreate);
+  try
+    aRes.ItemData.Position:=0;
+    fs.CopyFrom(aRes.ItemData,aRes.ItemData.Size);
+  finally
+    fs.Free;
+  end;
+end;
+{$ENDIF}
+
+{$IFDEF DUMPCURSOR}
+procedure DumpCursor(aRes : TGroupCursorResource);
+var fs : TFileStream;
+begin
+  fs:=TFileStream.Create(aRes.Name.Name+'.cur',fmCreate);
+  try
+    aRes.ItemData.Position:=0;
+    fs.CopyFrom(aRes.ItemData,aRes.ItemData.Size);
+  finally
+    fs.Free;
+  end;
+end;
+{$ENDIF}
+
+procedure DumpStream(aRes : TAbstractResource);
+var fs : TFileStream;
+begin
+  fs:=TFileStream.Create(aRes.Name.Name,fmCreate);
+  try
+    aRes.RawData.Position:=0;
+    fs.CopyFrom(aRes.RawData,aRes.RawData.Size);
+  finally
+    fs.Free;
+  end;
+end;
+
+function ProductVersion2Str(aData : TFileProductVersion) : string;
+begin
+  Result:=Format('%d,%d,%d,%d',[aData[0],aData[1],aData[2],aData[3]]);
+end;
+
+{$IFDEF PRINTVERSION}
+procedure PrintVersion(aRes : TVersionResource);
+var i,j : integer;
+begin
+  writeln(Format('File Version: %s',[ProductVersion2Str(aRes.FixedInfo.FileVersion)]));
+  writeln(Format('Product Version: %s',[ProductVersion2Str(aRes.FixedInfo.ProductVersion)]));
+  writeln(Format('File Flags Mask: %.8x',[aRes.FixedInfo.FileFlagsMask]));
+  writeln(Format('File Flags: %.8x',[aRes.FixedInfo.FileFlags]));
+  writeln(Format('File OS: %.8x',[aRes.FixedInfo.FileOS]));
+  writeln(Format('File Type: %.8x',[aRes.FixedInfo.FileType]));
+  writeln(Format('File SubType: %.8x',[aRes.FixedInfo.FileSubType]));
+  writeln(Format('File Date: %.16x',[aRes.FixedInfo.FileDate]));
+  for i:=0 to aRes.StringFileInfo.Count-1 do
+  begin
+    writeln('  StringTable ',aRes.StringFileInfo[i].Name);
+    for j:=0 to aRes.StringFileInfo[i].Count-1 do
+      writeln('    ',aRes.StringFileInfo[i].Keys[j],' = ',aRes.StringFileInfo[i].ValuesByIndex[j]);
+  end;
+  writeln('  VarFileInfo:');
+  for i:=0 to aRes.VarFileInfo.Count-1 do
+    writeln(Format('    Translation: language = %d, codepage = %d',[aRes.VarFileInfo[i].language,aRes.VarFileInfo[i].codepage]));
+end;
+{$ENDIF}
+
+
+{$IFDEF PRINTACCELERATORS}
+procedure PrintAccelerators(aRes : TAcceleratorsResource);
+var i : integer;
+    acc : TAccelerator;
+begin
+  for i:=0 to aRes.Count-1 do
+  begin
+    acc:=aRes[i];
+    writeln(Format('Flags = %.4x, Ansi = %.4x, ID = %.4x',[acc.Flags,acc.Ansi,acc.ID]));
+  end;
+end;
+{$ENDIF}
+
+procedure PrintData(aStream : TStream);
+var toread : integer;
+    sig : array[0..3] of char;
+begin
+  {$IFDEF PARSEDFM}
+  aStream.Position:=0;
+  aStream.ReadBuffer(sig,4);
+  aStream.Position:=0;
+  if sig='TPF0' then PrintDFM(aStream)
+  else
+  {$ENDIF}
+  while aStream.Position<aStream.Size do
+  begin
+    toread:=16;
+    if (aStream.Size-aStream.Position) < toread then
+      toread:=aStream.Size-aStream.Position;
+    PrintRow(aStream,toread);
+  end;
+end;
+
+procedure PrintResInfo(aRes : TAbstractResource);
+begin
+  writeln(Format('Resource Type = %s Name = %s',[ResTypeToStr(aRes._Type),aRes.Name.Name]));
+  writeln('  DataSize        = ',ares.DataSize);
+  writeln('  HeaderSize      = ',ares.HeaderSize);
+  writeln('  DataVersion     = ',ares.DataVersion);
+  writeln('  MemoryFlags     = ',MemFlagsToStr(ares.MemoryFlags));
+  writeln('  LanguageID      = ',ares.LangID);
+  writeln('  Version         = ',ares.Version);
+  writeln('  Characteristics = ',ares.Characteristics);
+  writeln('  DataOffset      = ',IntToHex(ares.DataOffset,8));
+  writeln;
+  writeln('  Data: ');
+  {$IFDEF PARSESTRINGTABLE}
+  if aRes is TStringTableResource then
+    PrintStringTable(aRes as TStringTableResource)
+  else
+  {$ENDIF}
+  {$IFDEF DUMPBITMAP}
+  if aRes is TBitmapResource then
+    DumpBitmap(aRes as TBitmapResource)
+  else
+  {$ENDIF}
+  {$IFDEF DUMPICON}
+  if aRes is TGroupIconResource then
+    DumpIcon(aRes as TGroupIconResource)
+  else
+  {$ENDIF}
+  {$IFDEF DUMPCURSOR}
+  if aRes is TGroupCursorResource then
+    DumpCursor(aRes as TGroupCursorResource)
+  else
+  {$ENDIF}
+  {$IFDEF PRINTVERSION}
+  if aRes is TVersionResource then
+    PrintVersion(aRes as TVersionResource)
+  else
+  {$ENDIF}
+  {$IFDEF PRINTACCELERATORS}
+  if aRes is TAcceleratorsResource then
+    PrintAccelerators(aRes as TAcceleratorsResource)
+  else
+  {$ENDIF}
+  {$DEFINE DISABILITATO}
+  {$IFDEF DISABILITATO}
+  if aRes._Type.DescType=dtID then
+    case aRes._Type.ID of
+      RT_HTML,RT_MANIFEST : DumpStream(aRes);
+//      RT_ACCELERATOR : PrintData(aRes.RawData);
+    end;
+  {$ENDIF}
+  PrintData(aRes.RawData);
+end;
+
+var res : TResources;
+    i : integer;
+
+begin
+  if not fileexists(paramstr(1)) then
+  begin
+    writeln('No filename specified.');
+    halt(1);
+  end;
+  res:=TResources.Create;
+  try
+    res.LoadFromFile(paramstr(1));
+    if paramcount>=2 then
+      res.WriteToFile(paramstr(2))
+    else
+      for i:=0 to res.Count-1 do
+        PrintResInfo(res[i]);
+  finally
+    res.Free;
+  end;
+end.
+

+ 348 - 0
packages/fcl-res/src/resdatastream.pp

@@ -0,0 +1,348 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Stream classes to provide copy-on-write functionality
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit resdatastream;
+
+{$MODE OBJFPC}
+
+interface
+
+uses Classes, SysUtils, resource;
+
+type
+
+  TCachedDataStream = class (TStream)
+  private
+  protected
+    fStream : TStream;
+    fSize : int64;
+    fPosition : int64;
+    function  GetPosition: Int64; override;
+    procedure SetPosition(const Pos: Int64); override;
+    function  GetSize: Int64; override;
+    procedure SetSize64(const NewSize: Int64); override;
+    procedure SetSize(NewSize: Longint); override;
+    procedure SetSize(const NewSize: Int64); override;
+  public
+    constructor Create(aStream : TStream; aResource : TAbstractResource; aSize : int64); virtual;
+    function Write(const Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
+  end;
+
+
+  { TCachedResourceDataStream }
+
+  TCachedResourceDataStream = class (TCachedDataStream)
+  private
+    fOffset : int64;
+  protected
+  public
+    constructor Create(aStream : TStream; aResource : TAbstractResource; aSize : int64); override;
+    function Read(var Buffer; Count: Longint): Longint; override;
+  end;
+  
+  TCachedStreamClass = class of TCachedDataStream;
+  
+
+  TUnderlyingStreamType = (usCached, usMemory, usCustom);
+
+  { TResourceDataStream }
+
+  TResourceDataStream = class(TStream)
+  private
+    fStream : TStream;
+    fStreamType : TUnderlyingStreamType;
+    fResource : TAbstractResource;
+    procedure CheckChangeStream;
+    function GetCached : boolean;
+    procedure SetCached(aValue : boolean);
+  protected
+    function  GetPosition: Int64; override;
+    procedure SetPosition(const Pos: Int64); override;
+    function  GetSize: Int64; override;
+    procedure SetSize64(const NewSize: Int64); override;
+    procedure SetSize(NewSize: Longint); override;
+    procedure SetSize(const NewSize: Int64); override;
+  public
+    constructor Create(aStream : TStream; aResource : TAbstractResource; aSize : int64; aClass: TCachedStreamClass);
+    destructor Destroy; override;
+    function Compare(aStream : TStream) : boolean;
+    procedure SetCustomStream(aStream : TStream);
+    function Read(var Buffer; Count: Longint): Longint; override;
+    function Write(const Buffer; Count: Longint): Longint; override;
+    function Seek(Offset: Longint; Origin: Word): Longint; override;
+    function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
+    property Cached : boolean read GetCached write SetCached;
+  end;
+  
+implementation
+
+{ TCachedDataStream }
+
+function TCachedDataStream.GetPosition: Int64;
+begin
+  Result:=fPosition;
+end;
+
+procedure TCachedDataStream.SetPosition(const Pos: Int64);
+begin
+  fPosition:=Pos;
+end;
+
+function TCachedDataStream.GetSize: Int64;
+begin
+  Result:=fSize;
+end;
+
+procedure TCachedDataStream.SetSize64(const NewSize: Int64);
+begin
+  raise EInvalidOperation.Create('');
+end;
+
+procedure TCachedDataStream.SetSize(NewSize: Longint);
+begin
+  SetSize64(NewSize);
+end;
+
+procedure TCachedDataStream.SetSize(const NewSize: Int64);
+begin
+ SetSize64(NewSize);
+end;
+
+constructor TCachedDataStream.Create(aStream: TStream;  aResource : TAbstractResource; aSize : int64);
+begin
+  fStream:=aStream;
+  fSize:=aSize;
+  fPosition:=0;
+end;
+
+function TCachedDataStream.Write(const Buffer; Count: Longint): Longint;
+begin
+  raise EInvalidOperation.Create('');
+end;
+
+function TCachedDataStream.Seek(Offset: Longint; Origin: Word
+  ): Longint;
+begin
+  Result:=Seek(Offset,TSeekOrigin(Origin));
+end;
+
+function TCachedDataStream.Seek(const Offset: Int64; Origin: TSeekOrigin
+  ): Int64;
+var newpos : int64;
+begin
+  case Origin of
+    soBeginning : newpos:=Offset;
+    soCurrent : newpos:=Position+Offset;
+    soEnd : newpos:=fSize-Offset;
+  end;
+  SetPosition(newpos);
+  Result:=Position;
+end;
+
+{ TCachedResourceDataStream }
+
+constructor TCachedResourceDataStream.Create(aStream: TStream;  aResource : TAbstractResource; aSize : int64);
+begin
+  inherited Create(aStream,aResource,aSize);
+  fOffset:=fStream.Position;
+end;
+
+function TCachedResourceDataStream.Read(var Buffer; Count: Longint): Longint;
+var oldpos : int64;
+begin
+  Result:=fSize-Position;
+  if Count<Result then Result:=Count;
+  if Result<0 then Result:=0;
+  if Result>0 then
+  begin
+    oldpos:=fStream.Position;
+    fStream.Position:=Position+fOffset;
+    Result:=fStream.Read(Buffer,Result);
+    fPosition:=fStream.Position-fOffset;
+    fStream.Position:=oldpos;
+  end;
+end;
+
+{ TResourceDataStream }
+
+procedure TResourceDataStream.CheckChangeStream;
+var NewStream : TMemoryStream;
+    oldpos : int64;
+begin
+  if fStreamType = usCached then
+  begin
+    NewStream:=TMemoryStream.Create;
+    try
+      oldpos:=fStream.Position;
+      fStream.Position:=0;
+      NewStream.CopyFrom(fStream,fStream.Size);
+      NewStream.Position:=oldpos;
+    except
+      NewStream.Free;
+      raise;
+    end;
+    fStream.Free;
+    fStream:=NewStream;
+    fStreamType:=usMemory;
+  end;
+end;
+
+function TResourceDataStream.GetCached: boolean;
+begin
+  Result:=fStreamType = usCached;
+end;
+
+procedure TResourceDataStream.SetCached(aValue: boolean);
+begin
+  if aValue=false then CheckChangeStream;
+end;
+
+function TResourceDataStream.GetPosition: Int64;
+begin
+  Result:=fStream.Position;
+end;
+
+procedure TResourceDataStream.SetPosition(const Pos: Int64);
+begin
+  fStream.Position:=Pos;
+end;
+
+function TResourceDataStream.GetSize: Int64;
+begin
+  Result:=fStream.Size;
+end;
+
+procedure TResourceDataStream.SetSize64(const NewSize: Int64);
+begin
+  CheckChangeStream;
+  fStream.Size:=NewSize;
+end;
+
+procedure TResourceDataStream.SetSize(NewSize: Longint);
+begin
+  SetSize64(NewSize);
+end;
+
+procedure TResourceDataStream.SetSize(const NewSize: Int64);
+begin
+  SetSize64(NewSize);
+end;
+
+constructor TResourceDataStream.Create(aStream: TStream; aResource :
+  TAbstractResource; aSize : int64; aClass: TCachedStreamClass);
+begin
+  if aStream=nil then fStreamType:=usMemory
+  else fStreamType:=usCached;
+  case fStreamType of
+    usMemory : fStream:=TMemoryStream.Create;
+    usCached : fStream:=aClass.Create(aStream,aResource,aSize);
+  end;
+  fResource:=aResource;
+end;
+
+destructor TResourceDataStream.Destroy;
+begin
+  if fStreamType<>usCustom then fStream.Free;
+end;
+
+function TResourceDataStream.Compare(aStream : TStream) : boolean;
+var tmp1, tmp2 : PtrUint;
+    b1,b2 : byte;
+    oldpos1,oldpos2 : int64;
+    tocompare : longword;
+begin
+  Result:=aStream=self;
+  if Result then exit;
+  Result:=aStream<>nil;
+  if not Result then exit;
+  Result:=Size=aStream.Size;
+  if not Result then exit;
+  oldpos1:=Position;
+  oldpos2:=aStream.Position;
+  Position:=0;
+  aStream.Position:=0;
+  tocompare:=Size;
+  while tocompare >= sizeof(PtrUInt) do
+  begin
+    ReadBuffer(tmp1,sizeof(PtrUInt));
+    aStream.ReadBuffer(tmp2,sizeof(PtrUInt));
+    Result:=tmp1=tmp2;
+    if not result then
+    begin
+      tocompare:=0;
+      break;
+    end;
+    dec(tocompare,sizeof(PtrUInt));
+  end;
+  while tocompare > 0 do
+  begin
+    ReadBuffer(b1,1);
+    aStream.ReadBuffer(b2,1);
+    Result:=b1=b2;
+    if not result then
+      break;
+    dec(tocompare);
+  end;
+  Position:=oldpos1;
+  aStream.Position:=oldpos2;
+end;
+
+procedure TResourceDataStream.SetCustomStream(aStream: TStream);
+begin
+  if fStreamType<>usCustom then fStream.Free;
+  if aStream=nil then
+  begin
+    fStream:=TMemoryStream.Create;
+    fStreamType:=usMemory;
+  end
+  else
+  begin
+    fStreamType:=usCustom;
+    fStream:=aStream;
+  end;
+end;
+
+function TResourceDataStream.Read(var Buffer; Count: Longint): Longint;
+begin
+  Result:=fStream.Read(Buffer,Count);
+end;
+
+function TResourceDataStream.Write(const Buffer; Count: Longint): Longint;
+begin
+  CheckChangeStream;
+  Result:=fStream.Write(Buffer,Count);
+end;
+
+function TResourceDataStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+  Result:=Seek(Offset,TSeekOrigin(Origin));
+end;
+
+function TResourceDataStream.Seek(const Offset: Int64; Origin: TSeekOrigin
+  ): Int64;
+var newpos : int64;
+begin
+  case Origin of
+    soBeginning : newpos:=Offset;
+    soCurrent : newpos:=Position+Offset;
+    soEnd : newpos:=Size-Offset;
+  end;
+  SetPosition(newpos);
+  Result:=Position;
+end;
+
+end.

+ 151 - 0
packages/fcl-res/src/resfactory.pp

@@ -0,0 +1,151 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Factory class for resources
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit resfactory;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+
+type
+  EResourceFactoryException = class(EResourceException);
+  EResourceClassAlreadyRegisteredException = class(EResourceFactoryException);
+  
+resourcestring
+  SAlreadyRegistered = 'A resource class for the type %s is already registered.';
+  
+type
+
+  { TResourceFactory }
+
+  TResourceFactory = class
+  private
+    class procedure InitResTypeList;
+    class procedure DisposeResTypeList;
+    class function FindResourceClass(aType : TResourceDesc) : TResourceClass;
+  protected
+  public
+    class procedure RegisterResourceClass(aType : TResID; aClass : TResourceClass); overload;
+    class procedure RegisterResourceClass(aType : TResName; aClass : TResourceClass); overload;
+    class procedure RegisterResourceClass(aType : TResourceDesc; aClass : TResourceClass); overload;
+    class function CreateResource(aType, aName : TResourceDesc) : TAbstractResource;
+  end;
+
+implementation
+
+type
+  TRegisteredResourceEntry = record
+    _type : TResourceDesc;
+    _class : TResourceClass;
+  end;
+  PRegisteredResourceEntry = ^TRegisteredResourceEntry;
+  
+var
+  ResTypeList : TFPList = nil;
+
+
+{ TResourceFactory }
+
+class procedure TResourceFactory.InitResTypeList;
+begin
+  if ResTypeList=nil then
+    ResTypeList:=TFPList.Create;
+end;
+
+class procedure TResourceFactory.DisposeResTypeList;
+var i : integer;
+    p : PRegisteredResourceEntry;
+begin
+  if ResTypeList=nil then exit;
+  for i:=0 to ResTypeList.Count-1 do
+  begin
+    p:=PRegisteredResourceEntry(ResTypeList[i]);
+    p^._type.Free;
+    FreeMem(p);
+  end;
+  FreeAndNil(ResTypeList);
+end;
+
+class function TResourceFactory.FindResourceClass(aType: TResourceDesc
+  ): TResourceClass;
+var i : integer;
+    p : PRegisteredResourceEntry;
+begin
+  InitResTypeList;
+  for i:=0 to ResTypeList.Count-1 do
+  begin
+    p:=PRegisteredResourceEntry(ResTypeList[i]);
+    if p^._type.Equals(aType) then
+    begin
+      Result:=p^._class;
+      exit;
+    end;
+  end;
+  Result:=nil;
+end;
+
+class procedure TResourceFactory.RegisterResourceClass(aType : TResID;
+  aClass : TResourceClass); overload;
+var t : TResourceDesc;
+begin
+  t:=TResourceDesc.Create(aType);
+  try
+    RegisterResourceClass(t,aClass);
+  finally
+    t.Free;
+  end;
+end;
+
+class procedure TResourceFactory.RegisterResourceClass(aType : TResName;
+  aClass : TResourceClass); overload;
+var t : TResourceDesc;
+begin
+  t:=TResourceDesc.Create(aType);
+  try
+    RegisterResourceClass(t,aClass);
+  finally
+    t.Free;
+  end;
+end;
+
+class procedure TResourceFactory.RegisterResourceClass(aType: TResourceDesc;
+  aClass: TResourceClass);
+var p : PRegisteredResourceEntry;
+begin
+  if FindResourceClass(aType)<>nil then
+    raise EResourceClassAlreadyRegisteredException.CreateFmt(SAlreadyRegistered,[aType.Name]);
+  p:=GetMem(sizeof(TRegisteredResourceEntry));
+  p^._type:=TResourceDesc.Create;
+  p^._type.Assign(aType);
+  p^._class:=aClass;
+  ResTypeList.Add(p);
+end;
+
+class function TResourceFactory.CreateResource(aType, aName: TResourceDesc
+  ): TAbstractResource;
+var theclass : TResourceClass;
+begin
+  theclass:=FindResourceClass(aType);
+  if theclass=nil then theclass:=TGenericResource;
+  Result:=theclass.Create(aType,aName);
+end;
+
+finalization
+  TResourceFactory.DisposeResTypeList;
+
+end.

+ 62 - 0
packages/fcl-res/src/resmerger.pp

@@ -0,0 +1,62 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Internal class to support merging of resources
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit resmerger;
+
+{$MODE OBJFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource,
+  stringtableresource,
+
+  //these two resource types know how to do it on their own... add them so that
+  //they got registered
+  groupiconresource, groupcursorresource;
+
+type
+
+  { TResourceMerger }
+
+  TResourceMerger = class
+  private
+  protected
+  public
+    class function Merge(aRes1, aRes2 : TAbstractResource) : boolean;
+  end;
+
+implementation
+
+{ TResourceMerger }
+
+class function TResourceMerger.Merge(aRes1, aRes2: TAbstractResource): boolean;
+var i : integer;
+    sRes1, sRes2 : TStringTableResource;
+begin
+  Result:=false;
+  if not (aRes1 is TStringTableResource) then exit;
+  sRes1:=TStringTableResource(aRes1);
+  sRes2:=TStringTableResource(aRes2);
+  //check if merging is possible...
+  for i:=sRes1.FirstID to sRes1.LastID do
+    if (sRes1[i]<>'') and (sRes2[i]<>'') then exit; //if both are used, no merging is possible
+  //ok, merge
+  for i:=sRes1.FirstID to sRes1.LastID do
+    if sRes2[i]<>'' then sRes1[i]:=sRes2[i];
+  Result:=true;
+end;
+
+end.

+ 1155 - 0
packages/fcl-res/src/resource.pp

@@ -0,0 +1,1155 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Base classes for resource handling
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit resource;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, Sysutils;
+
+const
+  RT_CURSOR       =  1;  //Hardware-dependent cursor resource.
+  RT_BITMAP       =  2;  //Bitmap resource.
+  RT_ICON         =  3;  //Hardware-dependent icon resource.
+  RT_MENU         =  4;  //Menu resource.
+  RT_DIALOG       =  5;  //Dialog box.
+  RT_STRING       =  6;  //String-table entry.
+  RT_FONTDIR      =  7;  //Font directory resource.
+  RT_FONT         =  8;  //Font resource.
+  RT_ACCELERATOR  =  9;  //Accelerator table.
+  RT_RCDATA       = 10;  //Application-defined resource (raw data).
+  RT_MESSAGETABLE = 11;  //Message-table entry.
+  RT_GROUP_CURSOR = 12;  //Hardware-independent cursor resource.
+  RT_GROUP_ICON   = 14;  //Hardware-independent icon resource.
+  RT_VERSION      = 16;  //Version resource.
+  RT_DLGINCLUDE   = 17;  //Never present in compiled form
+  RT_PLUGPLAY     = 19;  //Plug and Play resource.
+  RT_VXD          = 20;  //VXD.
+  RT_ANICURSOR    = 21;  //Animated cursor.
+  RT_ANIICON      = 22;  //Animated icon.
+  RT_HTML         = 23;  //HTML.
+  RT_MANIFEST     = 24;  //Microsoft Windows XP: Side-by-Side Assembly XML Manifest.
+
+  CREATEPROCESS_MANIFEST_RESOURCE_ID                 = 1;
+  ISOLATIONAWARE_MANIFEST_RESOURCE_ID                = 2;
+  ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID = 3;
+  MINIMUM_RESERVED_MANIFEST_RESOURCE_ID              = 1;   //inclusive
+  MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID              = 16;  //inclusive
+
+const
+  MF_MOVEABLE    = $0010;
+  MF_PURE        = $0020;
+  MF_PRELOAD     = $0040;
+  MF_DISCARDABLE = $1000;
+
+resourcestring
+  SReaderNotFoundExt   = 'Cannot find resource reader for extension ''%s''';
+  SReaderNotFoundProbe = 'Cannot find a resource reader: unknown format.';
+  SWriterNotFoundExt   = 'Cannot find resource writer for extension ''%s''';
+  SDescChangeNotAllowed = 'Cannot modify %s resource description';
+  SLangIDChangeNotAllowed = 'Cannot modify %s resource language ID';
+  SResDuplicate = 'Duplicate resource: Type = %s, Name = %s, Lang ID = %.4x';
+  SResourceNotFound = 'Cannot find resource: Type = %s, Name = %s';
+  SResourceNotFoundLang = 'Cannot find resource: Type = %s, Name = %s, Lang ID = %.4x';
+
+type
+  TLangID = word;
+  TResName = string;
+  TResID = LongWord;
+  TDescType = (dtName, dtID);
+
+type
+  EResourceException = class(Exception);
+  EResourceDescTypeException = class(EResourceException);
+  EResourceDescChangeNotAllowedException = class(EResourceException);
+  EResourceLangIDChangeNotAllowedException = class(EResourceException);
+  EResourceDuplicateException = class(EResourceException);
+  EResourceNotFoundException = class(EResourceException);
+  ENoMoreFreeIDsException = class(EResourceException);
+
+  EResourceReaderException = class(EResourceException);
+  EResourceReaderNotFoundException = class(EResourceReaderException);
+  EResourceReaderWrongFormatException = class(EResourceReaderException);
+  EResourceReaderUnexpectedEndOfStreamException = class (EResourceReaderException);
+
+  EResourceWriterException = class(EResourceException);
+  EResourceWriterNotFoundException = class(EResourceWriterException);
+
+type
+
+  TAbstractResource = class;
+
+  { TResourceDesc }
+
+  TResourceDesc = class
+  private
+    fName : TResName;
+    fID : TResID;
+    fDescType : TDescType;
+    fOwner : TAbstractresource;
+    
+    function GetID : TResID;
+    function GetName : TResName;
+    procedure SetID(const aID : TResID);
+    procedure SetName(const aName : TResName);
+    procedure CanChangeType(newType : TDescType);
+    procedure CanChangeValue;
+  protected
+    procedure SetOwner(aOwner : TAbstractResource);
+  public
+    constructor Create; overload;
+    constructor Create(const aID : TResID); overload;
+    constructor Create(const aName : TResName); overload;
+    procedure Assign(aResourceDesc : TResourceDesc);
+    function Equals(aResDesc : TResourceDesc) : boolean;
+    property Name : TResName read GetName write SetName;
+    property ID : TResID read GetID write SetID;
+    property DescType : TDescType read fDescType;
+  end;
+
+  TResources = class;
+
+  { TAbstractResource }
+
+  TAbstractResource = class
+  private
+    fLangId : TLangID;
+    fDataSize : longword;
+    fHeaderSize : longword;
+    fDataVersion : longword;
+    fMemoryFlags : word;
+    fVersion : longword;
+    fCharacteristics : longword;
+    fDataOffset : longword;
+    fCodePage : longword;
+    fRawData : TStream;
+    fOwnerList : TResources;
+    fOwner : TAbstractResource;
+    function GetRawData : TStream;
+    function GetCacheData : boolean;
+    procedure SetCacheData(const aValue : boolean);
+    function GetDataSize : longword;
+    procedure SetLangID(aLangID : TLangID);
+  protected
+    procedure SetDescOwner(aDesc : TResourceDesc);
+    procedure SetOwnerList(aResources : TResources); virtual;
+    procedure SetChildOwner(aChild : TAbstractResource);
+    function GetType : TResourceDesc; virtual; abstract;
+    function GetName : TResourceDesc; virtual; abstract;
+    function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; virtual; abstract;
+    function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; virtual; abstract;
+    procedure NotifyResourcesLoaded; virtual; abstract;
+    constructor Create; virtual; overload;
+  public
+    constructor Create(aType,aName : TResourceDesc); virtual; abstract; overload;
+    destructor Destroy; override;
+    function CompareContents(aResource: TAbstractResource): boolean; virtual;
+    procedure UpdateRawData; virtual; abstract;
+    procedure SetCustomRawDataStream(aStream : TStream);
+    property _Type : TResourceDesc read GetType;
+    property Name : TResourceDesc read GetName;
+    property LangID : TLangID read fLangID write SetLangID;
+    property DataSize : longword read GetDataSize;
+    property HeaderSize : longword read fHeaderSize;
+    property DataVersion : longword read fDataVersion write fDataVersion;
+    property MemoryFlags : word read fMemoryFlags write fMemoryFlags;
+    property Version : longword read fVersion write fVersion;
+    property Characteristics : longword read fCharacteristics write fCharacteristics;
+    property DataOffset : longword read fDataOffset;
+    property CodePage : longword read fCodePage write fCodePage;
+    property RawData : TStream read GetRawData;
+    property CacheData : boolean read GetCacheData write SetCacheData;
+    property OwnerList : TResources read fOwnerList;
+    property Owner : TAbstractResource read fOwner;
+  end;
+  
+  TResourceClass = class of TAbstractResource;
+  
+  { TGenericResource }
+
+  TGenericResource = class(TAbstractResource)
+  private
+    fType : TResourceDesc;
+    fName : TResourceDesc;
+  protected
+    function GetType : TResourceDesc; override;
+    function GetName : TResourceDesc; override;
+    function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
+    function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
+    procedure NotifyResourcesLoaded; override;
+  public
+    constructor Create(aType,aName : TResourceDesc); override;
+    destructor Destroy; override;
+    procedure UpdateRawData; override;
+  end;
+
+type
+  TAbstractResourceReader = class;
+  TAbstractResourceWriter = class;
+  TResourceReaderClass = class of TAbstractResourceReader;
+  TResourceWriterClass = class of TAbstractResourceWriter;
+
+  { TResources }
+
+  TResources = class
+  private
+    fList : TFPList;
+    fTree : TObject;
+    dummyType : TResourceDesc;
+    dummyName : TResourceDesc;
+    fCacheData : boolean;
+    fMoveFromCount : integer;
+    fRemovedCount : integer;
+    function GetItem(index : integer) : TAbstractResource;
+    function GetCount : longword;
+    procedure SetCacheData(const aValue : boolean);
+    procedure NotifyLoaded;
+//  protected
+  private
+    fTempRStream : TStream;
+    class procedure InitReaderList;
+    class procedure InitWriterList;
+    class procedure DisposeStreamerList(aList : TFPList);
+    class procedure DisposeReaderList;
+    class procedure DisposeWriterList;
+    class function FindWriterClass(aExtension : string) : TResourceWriterClass;
+    class procedure RegisterStreamer(aList : TFPList; aExtension : string; aClass : TClass);
+
+    procedure SendUpdateRawData;
+    procedure InternalRemove(aResource: TAbstractResource);
+    procedure InternalRemove(aIndex : integer);
+    procedure QuietRemove(aResource : TAbstractResource; aIndex : integer; aIndexValid : boolean);
+    procedure InternalClear;
+    procedure InternalAdd(aResource : TAbstractResource; prevIdx : integer; prevIdxValid : boolean);
+    procedure AddNoTree(aResource : TAbstractResource);
+    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
+    function InternalFind(aType, aName : TResourceDesc) : TAbstractResource; overload;
+    procedure BeginMoveFrom;
+    procedure EndMoveFrom;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Add(aResource : TAbstractResource);
+    function AddAutoID(aResource : TAbstractResource) : TResID;
+    procedure Clear;
+    function Find(aType, aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
+    function Find(aType, aName : TResourceDesc) : TAbstractResource; overload;
+    function Find(const aType : TResName; const aName : TResName; const aLangID : TLangID) : TAbstractResource; overload;
+    function Find(const aType : TResName; const aName : TResID; const aLangID : TLangID) : TAbstractResource; overload;
+    function Find(const aType : TResID; const aName : TResName; const aLangID : TLangID) : TAbstractResource; overload;
+    function Find(const aType : TResID; const aName : TResID; const aLangID : TLangID) : TAbstractResource; overload;
+    function Find(const aType : TResName; const aName : TResName) : TAbstractResource; overload;
+    function Find(const aType : TResName; const aName : TResID) : TAbstractResource; overload;
+    function Find(const aType : TResID; const aName : TResName) : TAbstractResource; overload;
+    function Find(const aType : TResID; const aName : TResID) : TAbstractResource; overload;
+    class function FindReader(aStream: TStream; aExtension: string) : TAbstractResourceReader;
+    class function FindReader(aStream : TStream) : TAbstractResourceReader;
+    procedure MoveFrom(aResources : TResources);
+    function Remove(aType,aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
+    function Remove(aType,aName : TResourceDesc) : TAbstractResource; overload;
+    function Remove(aResource : TAbstractResource) : TAbstractResource; overload;
+    function Remove(aIndex : integer) : TAbstractResource; overload;
+    procedure LoadFromStream(aStream : TStream); overload;
+    procedure LoadFromStream(aStream : TStream; aReader : TAbstractResourceReader); overload;
+    procedure LoadFromFile(aFileName : string); overload;
+    procedure LoadFromFile(aFileName : string; aReader : TAbstractResourceReader); overload;
+    class procedure RegisterReader(const aExtension : string; aClass : TResourceReaderClass);
+    class procedure RegisterWriter(const aExtension : string; aClass : TResourceWriterClass);
+    procedure WriteToStream(aStream : TStream; aWriter : TAbstractResourceWriter);
+    procedure WriteToFile(aFileName : string); overload;
+    procedure WriteToFile(aFileName : string; aWriter : TAbstractResourceWriter); overload;
+    property Count : longword read GetCount;
+    property Items[Index : integer] : TAbstractResource read GetItem; default;
+    property CacheData : boolean read fCacheData write SetCacheData;
+  end;
+
+  { TAbstractResourceReader }
+
+  TAbstractResourceReader = class
+  private
+  protected
+    procedure SetDataSize(aResource : TAbstractResource; aValue : longword);
+    procedure SetHeaderSize(aResource : TAbstractResource; aValue : longword);
+    procedure SetDataOffset(aResource : TAbstractResource; aValue : longword);
+    procedure SetRawData(aResource : TAbstractResource; aStream : TStream);
+    procedure CallSubReaderLoad(aReader: TAbstractResourceReader; aResources : TResources; aStream : TStream);
+    procedure AddNoTree(aResources : TResources; aResource: TAbstractResource);
+    function GetTree(aResources : TResources) : TObject;
+    function GetExtensions : string; virtual; abstract;
+    function GetDescription : string; virtual; abstract;
+    procedure Load(aResources : TResources; aStream : TStream); virtual; abstract;
+    function CheckMagic(aStream : TStream) : boolean; virtual; abstract;
+  public
+    constructor Create; virtual; abstract;
+    property Extensions : string read GetExtensions;
+    property Description : string read GetDescription;
+  end;
+
+  { TAbstractResourceWriter }
+
+  TAbstractResourceWriter = class
+  private
+  protected
+    function GetTree(aResources : TResources) : TObject;
+    function GetExtensions : string; virtual; abstract;
+    function GetDescription : string; virtual; abstract;
+    procedure Write(aResources : TResources; aStream : TStream); virtual; abstract;
+  public
+    constructor Create; virtual; abstract;
+    property Extensions : string read GetExtensions;
+    property Description : string read GetDescription;
+  end;
+
+implementation
+
+uses resdatastream, resourcetree, resmerger;
+
+type
+  PRegisteredStreamerEntry = ^TRegisteredStreamerEntry;
+  TRegisteredStreamerEntry = record
+    ext : shortstring;
+    _class : TClass;
+    next : PRegisteredStreamerEntry;
+  end;
+
+var RegisteredReaders : TFPList = nil;
+    RegisteredWriters : TFPList = nil;
+
+{ TResourceDesc }
+
+function TResourceDesc.GetID: TResID;
+begin
+  if fDescType<>dtId then
+    raise EResourceDescTypeException.Create('');
+  Result:=fId;
+end;
+
+function TResourceDesc.GetName: TResName;
+begin
+  if fDescType = dtName then
+    Result:=fName
+  else Result:=IntToStr(fId);
+end;
+
+procedure TResourceDesc.CanChangeType(newType : TDescType);
+begin
+  if fOwner=nil then exit;
+  if newType=fDescType then exit;
+  if (fOwner.OwnerList<>nil) or (not fOwner.ChangeDescTypeAllowed(self)) then
+    raise EResourceDescChangeNotAllowedException.CreateFmt(SDescChangeNotAllowed,[Name]);
+end;
+
+procedure TResourceDesc.CanChangeValue;
+begin
+  if fOwner=nil then exit;
+  if (fOwner.OwnerList<>nil) or (not fOwner.ChangeDescValueAllowed(self)) then
+    raise EResourceDescChangeNotAllowedException.CreateFmt(SDescChangeNotAllowed,[Name]);
+end;
+
+procedure TResourceDesc.SetOwner(aOwner: TAbstractResource);
+begin
+  fOwner:=aOwner;
+end;
+
+procedure TResourceDesc.SetID(const aID: TResID);
+begin
+  CanChangeType(dtID);
+  CanChangeValue;
+  fDescType:=dtID;
+  fId:=aID;
+end;
+
+procedure TResourceDesc.SetName(const aName: TResName);
+begin
+  CanChangeType(dtName);
+  CanChangeValue;
+  fDescType:=dtName;
+  fName:=UpperCase(aName);
+end;
+
+constructor TResourceDesc.Create;
+begin
+  fName:='';
+  fID:=0;
+  fDescType:=dtName;
+  fOwner:=nil;
+end;
+
+constructor TResourceDesc.Create(const aID: TResID);
+begin
+  Create;
+  SetID(aID);
+end;
+
+constructor TResourceDesc.Create(const aName: TResName);
+begin
+  Create;
+  SetName(aName);
+end;
+
+procedure TResourceDesc.Assign(aResourceDesc: TResourceDesc);
+begin
+  CanChangeType(aResourceDesc.fDescType);
+  CanChangeValue;
+  fDescType:=aResourceDesc.fDescType;
+  case fDescType of
+    dtID   : begin fID:=aResourceDesc.fID; fName:=''; end;
+    dtName : begin fName:=aResourceDesc.fName; fID:=0; end;
+  end;
+end;
+
+function TResourceDesc.Equals(aResDesc: TResourceDesc): boolean;
+begin
+  Result:=aResDesc.DescType=fDescType;
+  if not Result then exit;
+  case fDescType of
+    dtName : Result:=aResDesc.Name=fName;
+    dtID   : Result:=aResDesc.ID=fID;
+  end;
+end;
+
+{ TAbstractResource }
+
+function TAbstractResource.GetRawData: TStream;
+begin
+  if fRawData = nil then
+    fRawData:=TResourceDataStream.Create(nil,self,DataSize,TCachedResourceDataStream);
+  Result:=fRawData;
+end;
+
+function TAbstractResource.GetCacheData: boolean;
+begin
+  Result:=TResourceDataStream(RawData).Cached;
+end;
+
+procedure TAbstractResource.SetCacheData(const aValue: boolean);
+begin
+  TResourceDataStream(RawData).Cached:=aValue;
+end;
+
+function TAbstractResource.GetDataSize: longword;
+begin
+  if fRawData=nil then Result:=fDataSize
+  else Result:=fRawData.Size;
+end;
+
+procedure TAbstractResource.SetLangID(aLangID: TLangID);
+begin
+  if OwnerList<>nil then
+    raise EResourceLangIDChangeNotAllowedException.CreateFmt(SLangIDChangeNotAllowed,[Name]);
+  fLangId:=aLangID;
+end;
+
+procedure TAbstractResource.SetDescOwner(aDesc: TResourceDesc);
+begin
+  aDesc.SetOwner(self);
+end;
+
+procedure TAbstractResource.SetOwnerList(aResources: TResources);
+begin
+  fOwnerList:=aResources;
+end;
+
+procedure TAbstractResource.SetChildOwner(aChild: TAbstractResource);
+begin
+  aChild.fOwner:=self;
+end;
+
+constructor TAbstractResource.Create;
+begin
+  fLangID:=0;
+  
+  fDataSize:=0;
+  fHeaderSize:=0;
+  fDataVersion:=0;
+  fMemoryFlags:=MF_MOVEABLE or MF_DISCARDABLE;
+  fVersion:=0;
+  fCharacteristics:=0;
+  fDataOffset:=0;
+  fCodePage:=0;
+  fRawData:=nil;
+  fOwnerList:=nil;
+  fOwner:=nil;
+end;
+
+destructor TAbstractResource.Destroy;
+begin
+  if fRawData<>nil then fRawData.Free;
+end;
+
+function TAbstractResource.CompareContents(aResource: TAbstractResource
+  ): boolean;
+begin
+  Result:=TResourceDataStream(RawData).Compare(aResource.RawData);
+end;
+
+procedure TAbstractResource.SetCustomRawDataStream(aStream: TStream);
+begin
+  TResourceDataStream(RawData).SetCustomStream(aStream);
+end;
+
+{ TResources }
+
+function TResources.GetItem(index: integer): TAbstractResource;
+begin
+  Result:=TAbstractResource(fList[index]);
+end;
+
+function TResources.GetCount: longword;
+begin
+  Result:=fList.Count;
+end;
+
+procedure TResources.SetCacheData(const aValue: boolean);
+var i : integer;
+begin
+  if aValue=fCacheData then exit;
+  fCacheData:=aValue;
+  if fCacheData then exit;  //single resources cache data by default
+  //don't cache data: load everything and free the temporary stream.
+  for i:=0 to Count-1 do
+    Items[i].CacheData:=aValue;
+  if fTempRStream<>nil then FreeAndNil(fTempRStream);
+end;
+
+procedure TResources.NotifyLoaded;
+var i : integer;
+begin
+  for i:=0 to Count-1 do
+    Items[i].NotifyResourcesLoaded;
+end;
+
+class procedure TResources.InitReaderList;
+begin
+  if RegisteredReaders=nil then
+    RegisteredReaders:=TFPList.Create;
+end;
+
+class procedure TResources.InitWriterList;
+begin
+  if RegisteredWriters=nil then
+    RegisteredWriters:=TFPList.Create;
+end;
+
+class procedure TResources.DisposeStreamerList(aList: TFPList);
+var p,p2 : PRegisteredStreamerEntry;
+    i : integer;
+begin
+  if aList=nil then exit;
+  for i:=0 to aList.Count-1 do
+  begin
+    p:=PRegisteredStreamerEntry(aList[i]);
+    while p<>nil do
+    begin
+      p2:=p^.next;
+      Freemem(p);
+      p:=p2;
+    end;
+  end;
+end;
+
+class procedure TResources.DisposeReaderList;
+begin
+  DisposeStreamerList(RegisteredReaders);
+  FreeAndNil(RegisteredReaders);
+end;
+
+class procedure TResources.DisposeWriterList;
+begin
+  DisposeStreamerList(RegisteredWriters);
+  FreeAndNil(RegisteredWriters);
+end;
+
+class function TResources.FindReader(aStream: TStream; aExtension: string) :
+  TAbstractResourceReader;
+var i : integer;
+    p : PRegisteredStreamerEntry;
+    position : int64;
+    found : boolean;
+begin
+  Result:=nil;
+  InitReaderList;
+  position:=aStream.Position;
+  aExtension:=lowercase(aExtension);
+  for i:=0 to RegisteredReaders.Count-1 do
+  begin
+    p:=PRegisteredStreamerEntry(RegisteredReaders[i]);
+    if p^.ext=aExtension then //try all readers registered for this extension
+    begin
+      while p<>nil do
+      begin
+        Result:=TResourceReaderClass(p^._class).Create;
+        found:=Result.CheckMagic(aStream);
+        aStream.Position:=position; //rewind
+        if found then exit;
+        FreeAndNil(Result);
+        p:=p^.next;
+      end;
+      // There are readers for this extension, but no one seems to be able
+      // to read the file.
+      // So, return the first reader, and it will fail later.
+      p:=PRegisteredStreamerEntry(RegisteredReaders[i]);
+      Result:=TResourceReaderClass(p^._class).Create;
+      exit;
+    end;
+  end;
+  raise EResourceReaderNotFoundException.Create(Format(SReaderNotFoundExt,[aExtension]));
+end;
+
+class function TResources.FindReader(aStream: TStream
+  ): TAbstractResourceReader;
+var i : integer;
+    p : PRegisteredStreamerEntry;
+    position : int64;
+    found : boolean;
+begin
+  Result:=nil;
+  InitReaderList;
+  position:=aStream.Position;
+  for i:=0 to RegisteredReaders.Count-1 do
+  begin
+    p:=PRegisteredStreamerEntry(RegisteredReaders[i]);
+    while p<>nil do
+    begin
+      Result:=TResourceReaderClass(p^._class).Create;
+      found:=Result.CheckMagic(aStream);
+      aStream.Position:=position; //rewind
+      if found then exit;
+      FreeAndNil(Result);
+      p:=p^.next;
+    end;
+  end;
+  raise EResourceReaderNotFoundException.Create(SReaderNotFoundProbe);
+end;
+
+procedure TResources.MoveFrom(aResources: TResources);
+var res : TAbstractResource;
+    i : integer;
+begin
+  aResources.BeginMoveFrom;
+  try
+    for i:=0 to aResources.Count-1 do
+    begin
+      res:=aResources.Items[i];
+      if res=nil then continue;
+      if res.Owner<>nil then           //If we are adding an owned resource, add
+        InternalAdd(res.Owner,0,false) //the owner resource instead (it will take
+      else                             //care of adding its sub-resources)
+        InternalAdd(res,i,true);
+    end;
+  finally
+    aResources.EndMoveFrom;
+  end;
+end;
+
+class function TResources.FindWriterClass(aExtension: string
+  ): TResourceWriterClass;
+var i : integer;
+    p : PRegisteredStreamerEntry;
+begin
+  Result:=nil;
+  InitWriterList;
+  aExtension:=lowercase(aExtension);
+  for i:=0 to RegisteredWriters.Count-1 do
+  begin
+    p:=PRegisteredStreamerEntry(RegisteredWriters[i]);
+    if p^.ext=aExtension then
+    begin
+      Result:=TResourceWriterClass(p^._class);
+      exit;
+    end;
+  end;
+  raise EResourceWriterNotFoundException.Create(Format(SWriterNotFoundExt,[aExtension]));
+end;
+
+procedure TResources.InternalAdd(aResource : TAbstractResource; prevIdx :
+  integer; prevIdxValid : boolean);
+var resold : TAbstractResource;
+begin
+  resold:=InternalFind(aResource._Type,aResource.Name,aResource.LangID);
+  if resold<>nil then
+  begin
+    if TResourceMerger.Merge(resold,aResource) then exit;
+    raise EResourceDuplicateException.CreateFmt(SResDuplicate,[aResource._Type.Name,aResource.Name.Name,aResource.LangID]);
+  end;
+  fList.Add(aResource);
+  TRootResTreeNode(fTree).Add(aResource);
+  if aResource.OwnerList<>nil then
+    aResource.OwnerList.QuietRemove(aResource,prevIdx,prevIdxValid);
+  aResource.SetOwnerList(self);
+  aResource.CacheData:=fCacheData;
+end;
+
+procedure TResources.AddNoTree(aResource: TAbstractResource);
+begin
+  fList.Add(aResource);
+  aResource.SetOwnerList(self);
+  aResource.CacheData:=fCacheData;
+end;
+
+function TResources.InternalFind(aType, aName: TResourceDesc;
+  const aLangID: TLangID): TAbstractResource;
+begin
+  Result:=TRootResTreeNode(fTree).Find(aType,aName,aLangID);
+end;
+
+function TResources.InternalFind(aType, aName: TResourceDesc
+  ): TAbstractResource;
+begin
+  Result:=TRootResTreeNode(fTree).Find(aType,aName);
+end;
+
+procedure TResources.BeginMoveFrom;
+begin
+  inc(fMoveFromCount);
+  fRemovedCount:=0;
+end;
+
+procedure TResources.EndMoveFrom;
+begin
+  dec(fMoveFromCount);
+  if fMoveFromCount=0 then
+    if fRemovedCount=fList.Count then //all items removed: clear the list
+      fList.Clear
+    else
+      fList.Pack; //for some reason, not all items were removed. remove only nils
+end;
+
+procedure TResources.Add(aResource: TAbstractResource);
+begin
+  InternalAdd(aResource,0,false);
+end;
+
+function TResources.AddAutoID(aResource: TAbstractResource): TResID;
+var newid : TResID;
+begin
+  newid:=TRootResTreeNode(fTree).FindFreeID(aResource._Type);
+
+  //if we reached this point, ENoMoreFreeIDsException hasn't been raised.
+  if aResource.OwnerList<>nil then aResource.OwnerList.Remove(aResource);
+  aResource.Name.ID:=newid;
+  InternalAdd(aResource,0,false);
+  Result:=newid;
+end;
+
+//clear without freeing fTempRStream
+procedure TResources.InternalClear;
+var i : integer;
+begin
+  TRootResTreeNode(fTree).Clear;
+  for i:=0 to Count-1 do
+    TAbstractResource(fList[i]).Free;
+  fList.Clear;
+end;
+
+procedure TResources.Clear;
+begin
+  InternalClear;
+  if fTempRStream<>nil then FreeAndNil(fTempRStream);
+end;
+
+function TResources.Find(aType, aName: TResourceDesc; const aLangID : TLangID):
+  TAbstractResource;
+begin
+  Result:=TRootResTreeNode(fTree).Find(aType,aName,aLangID);
+  if Result=nil then
+    raise EResourceNotFoundException.CreateFmt(SResourceNotFoundLang,[aType.Name,aName.Name,aLangID]);
+end;
+
+function TResources.Find(aType, aName: TResourceDesc):
+  TAbstractResource;
+begin
+  Result:=TRootResTreeNode(fTree).Find(aType,aName);
+  if Result=nil then
+    raise EResourceNotFoundException.CreateFmt(SResourceNotFound,[aType.Name,aName.Name]);
+end;
+
+function TResources.Find(const aType: TResName; const aName: TResName; const
+  aLangID : TLangID): TAbstractResource;
+begin
+  dummyType.Name:=aType;
+  dummyName.Name:=aName;
+  Result:=Find(dummyType,dummyName,aLangID);
+end;
+
+function TResources.Find(const aType: TResName; const aName: TResID; const
+  aLangID : TLangID  ): TAbstractResource;
+begin
+  dummyType.Name:=aType;
+  dummyName.ID:=aName;
+  Result:=Find(dummyType,dummyName,aLangID);
+end;
+
+function TResources.Find(const aType: TResID; const aName: TResName; const
+  aLangID : TLangID  ): TAbstractResource;
+begin
+  dummyType.ID:=aType;
+  dummyName.Name:=aName;
+  Result:=Find(dummyType,dummyName,aLangID);
+end;
+
+function TResources.Find(const aType: TResID; const aName: TResID; const
+  aLangID : TLangID  ): TAbstractResource;
+begin
+  dummyType.ID:=aType;
+  dummyName.ID:=aName;
+  Result:=Find(dummyType,dummyName,aLangID);
+end;
+
+function TResources.Find(const aType: TResName; const aName: TResName
+  ): TAbstractResource;
+begin
+  dummyType.Name:=aType;
+  dummyName.Name:=aName;
+  Result:=Find(dummyType,dummyName);
+end;
+
+function TResources.Find(const aType: TResName; const aName: TResID
+  ): TAbstractResource;
+begin
+  dummyType.Name:=aType;
+  dummyName.ID:=aName;
+  Result:=Find(dummyType,dummyName);
+end;
+
+function TResources.Find(const aType: TResID; const aName: TResName
+  ): TAbstractResource;
+begin
+  dummyType.ID:=aType;
+  dummyName.Name:=aName;
+  Result:=Find(dummyType,dummyName);
+end;
+
+function TResources.Find(const aType: TResID; const aName: TResID
+  ): TAbstractResource;
+begin
+  dummyType.ID:=aType;
+  dummyName.ID:=aName;
+  Result:=Find(dummyType,dummyName);
+end;
+
+function TResources.Remove(aType,aName : TResourceDesc;
+  const aLangID : TLangID) : TAbstractResource;
+begin
+  Result:=TRootResTreeNode(fTree).Remove(aType,aName,aLangID);
+  InternalRemove(Result);
+  Result.SetOwnerList(nil);
+end;
+
+function TResources.Remove(aType,aName : TResourceDesc) : TAbstractResource;
+begin
+  Result:=TRootResTreeNode(fTree).Remove(aType,aName);
+  InternalRemove(Result);
+  Result.SetOwnerList(nil);
+end;
+
+function TResources.Remove(aResource: TAbstractResource) : TAbstractResource;
+begin
+  InternalRemove(aResource);
+  Result:=TRootResTreeNode(fTree).Remove(aResource._Type,aResource.Name,aResource.LangID);
+  Result.SetOwnerList(nil);
+end;
+
+function TResources.Remove(aIndex: integer): TAbstractResource;
+begin
+  Result:=Items[aIndex];
+  InternalRemove(aIndex);
+  Result:=TRootResTreeNode(fTree).Remove(Result._Type,Result.Name,Result.LangID);
+  Result.SetOwnerList(nil);
+end;
+
+procedure TResources.InternalRemove(aResource: TAbstractResource);
+var idx : integer;
+begin
+  if aResource=nil then exit;
+  idx:=fList.IndexOf(aResource);
+  if idx=-1 then
+    raise EResourceNotFoundException.CreateFmt(SResourceNotFoundLang,[
+      aResource._Type.Name,aResource.Name.Name,aResource.LangID]);
+  if fMoveFromCount>0 then fList[idx]:=nil
+  else fList.Delete(idx);
+  inc(fRemovedCount);
+end;
+
+procedure TResources.InternalRemove(aIndex: integer);
+begin
+  if fMoveFromCount>0 then fList[aIndex]:=nil
+  else fList.Delete(aIndex);
+  inc(fRemovedCount);
+end;
+
+//removes without calling setownerlist
+procedure TResources.QuietRemove(aResource : TAbstractResource; aIndex :
+  integer; aIndexValid : boolean);
+begin
+  if aIndexValid then InternalRemove(aIndex)
+  else InternalRemove(aResource);
+  TRootResTreeNode(fTree).Remove(aResource._Type,aResource.Name,aResource.LangID);
+end;
+
+procedure TResources.LoadFromStream(aStream: TStream);
+var aReader : TAbstractResourceReader;
+begin
+  aReader:=FindReader(aStream);
+  try
+    LoadFromStream(aStream,aReader);
+  finally
+    aReader.Free;
+  end;
+end;
+
+procedure TResources.LoadFromStream(aStream: TStream;
+  aReader: TAbstractResourceReader);
+begin
+  InternalClear;
+  aReader.Load(self,aStream);
+  NotifyLoaded;
+end;
+
+procedure TResources.LoadFromFile(aFileName: string);
+var ext : string;
+    aReader : TAbstractResourceReader;
+begin
+  ext:=ExtractFileExt(aFileName);
+  if fTempRStream<>nil then FreeAndNil(fTempRStream);
+  fTempRStream:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
+  aReader:=FindReader(fTempRStream,ext);
+  try
+    LoadFromStream(fTempRStream,aReader);
+  finally
+    aReader.Free;
+    if not fCacheData then FreeAndNil(fTempRStream);
+  end;
+end;
+
+procedure TResources.LoadFromFile(aFileName: string;
+  aReader: TAbstractResourceReader);
+begin
+  if fTempRStream<>nil then FreeAndNil(fTempRStream);
+  fTempRStream:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
+  try
+    LoadFromStream(fTempRStream,aReader);
+  finally
+    if not fCacheData then FreeAndNil(fTempRStream);
+  end;
+end;
+
+class procedure TResources.RegisterStreamer(aList : TFPList; aExtension :
+  string; aClass : TClass);
+var newp,p : PRegisteredStreamerEntry;
+    i : integer;
+begin
+  aExtension:=lowercase(aExtension);
+  newp:=GetMem(sizeof(TRegisteredStreamerEntry));
+  newp^.next:=nil;
+  newp^.ext:=aExtension;
+  newp^._class:=aClass;
+
+  for i:=0 to aList.Count-1 do
+  begin
+    p:=PRegisteredStreamerEntry(aList[i]);
+    if p^.ext=aExtension then
+    begin
+      while p^.next<>nil do
+        p:=p^.next;
+      p^.next:=newp;
+      exit;
+    end;
+  end;
+  aList.Add(newp);
+end;
+
+procedure TResources.SendUpdateRawData;
+var i : integer;
+begin
+  for i:=0 to Count-1 do
+    Items[i].UpdateRawData;
+end;
+
+class procedure TResources.RegisterReader(const aExtension : string;
+  aClass: TResourceReaderClass);
+begin
+  InitReaderList;
+  RegisterStreamer(RegisteredReaders,aExtension,aClass);
+end;
+
+class procedure TResources.RegisterWriter(const aExtension : string;
+  aClass: TResourceWriterClass);
+begin
+  InitWriterList;
+  RegisterStreamer(RegisteredWriters,aExtension,aClass);
+end;
+
+procedure TResources.WriteToStream(aStream: TStream;
+  aWriter: TAbstractResourceWriter);
+begin
+  SendUpdateRawData;
+  aWriter.Write(self,aStream);
+end;
+
+procedure TResources.WriteToFile(aFileName: string);
+var ext : string;
+    aWriter : TAbstractResourceWriter;
+begin
+  ext:=ExtractFileExt(aFileName);
+  aWriter:=FindWriterClass(ext).Create;
+  try
+    WriteToFile(aFileName,aWriter);
+  finally
+    aWriter.Free;
+  end;
+end;
+
+procedure TResources.WriteToFile(aFileName: string;
+  aWriter: TAbstractResourceWriter);
+var OutStream : TFileStream;
+begin
+  OutStream:=TFileStream.Create(aFileName,fmCreate or fmShareDenyWrite);
+  try
+    WriteToStream(OutStream,aWriter);
+  finally
+    OutStream.Free;
+  end;
+end;
+
+constructor TResources.Create;
+begin
+  fList:=TFPList.Create;
+  fTree:=TRootResTreeNode.Create;
+  dummyType:=TResourceDesc.Create;
+  dummyName:=TResourceDesc.Create;
+  fTempRStream:=nil;
+  fCacheData:=true;
+  fMoveFromCount:=0;
+  fRemovedCount:=0;
+end;
+
+destructor TResources.Destroy;
+begin
+  Clear;
+  fList.Free;
+  fTree.Free;
+  dummyType.Free;
+  dummyName.Free;
+end;
+
+{ TAbstractResourceReader }
+
+procedure TAbstractResourceReader.SetDataSize(aResource: TAbstractResource;
+  aValue: longword);
+begin
+  aResource.fDataSize:=aValue;
+end;
+
+procedure TAbstractResourceReader.SetHeaderSize(aResource: TAbstractResource;
+  aValue: longword);
+begin
+  aResource.fHeaderSize:=aValue;
+end;
+
+procedure TAbstractResourceReader.SetDataOffset(aResource: TAbstractResource;
+  aValue: longword);
+begin
+  aResource.fDataOffset:=aValue;
+end;
+
+procedure TAbstractResourceReader.SetRawData(aResource: TAbstractResource;
+  aStream: TStream);
+begin
+  if aResource.fRawData<>nil then aResource.fRawData.Free; //should never happen!
+  aResource.fRawData:=aStream;
+end;
+
+procedure TAbstractResourceReader.CallSubReaderLoad(
+  aReader: TAbstractResourceReader; aResources: TResources; aStream: TStream);
+begin
+  aReader.Load(aResources,aStream);
+end;
+
+procedure TAbstractResourceReader.AddNoTree(aResources: TResources;
+  aResource: TAbstractResource);
+begin
+  aResources.AddNoTree(aResource);
+end;
+
+function TAbstractResourceReader.GetTree(aResources: TResources): TObject;
+begin
+  Result:=aResources.fTree;
+end;
+
+{ TGenericResource }
+
+function TGenericResource.ChangeDescTypeAllowed(aDesc: TResourceDesc): boolean;
+begin
+  Result:=true;
+end;
+
+function TGenericResource.ChangeDescValueAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=true;
+end;
+
+procedure TGenericResource.NotifyResourcesLoaded;
+begin
+end;
+
+procedure TGenericResource.UpdateRawData;
+begin
+end;
+
+function TGenericResource.GetType : TResourceDesc;
+begin
+  Result:=fType;
+end;
+
+function TGenericResource.GetName : TResourceDesc;
+begin
+  Result:=fName;
+end;
+
+constructor TGenericResource.Create(aType, aName: TResourceDesc);
+begin
+  Create;
+  fType:=TResourceDesc.Create;
+  fType.Assign(aType);
+  fName:=TResourceDesc.Create;
+  fName.Assign(aName);
+  SetDescOwner(fType);
+  SetDescOwner(fName);
+end;
+
+destructor TGenericResource.Destroy;
+begin
+  fName.Free;
+  fType.Free;
+  inherited Destroy;
+end;
+
+{ TAbstractResourceWriter }
+
+function TAbstractResourceWriter.GetTree(aResources: TResources): TObject;
+begin
+  Result:=aResources.fTree;
+end;
+
+finalization
+   TResources.DisposeReaderList;
+   TResources.DisposeWriterList;
+
+end.

+ 560 - 0
packages/fcl-res/src/resourcetree.pp

@@ -0,0 +1,560 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Implements an ordered tree of resources
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit resourcetree;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+
+type
+
+  { TResourceTreeNode }
+
+  TResourceTreeNode = class
+  protected
+    fParent : TResourceTreeNode;
+    fNamedEntries : TFPList;
+    fIDEntries : TFPList;
+    fSubDirRVA : longword;
+    fDataRVA : longword;
+    fNameRva : longword;
+    fDesc : TResourceDesc;
+    function GetNamedCount : longword;
+    function GetNamedEntry(index : integer) : TResourceTreeNode;
+    function GetIDCount : longword;
+    function GetIDEntry(index : integer) : TResourceTreeNode;
+    function GetData : TAbstractResource; virtual;
+    function InternalFind(aList : TFPList; aDesc : TResourceDesc; out index : integer) : boolean; overload;
+    function InternalFind(aList : TFPList; aLangID : TLangID; out index : integer) : boolean; overload;
+    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; virtual; abstract; overload;
+    constructor Create; virtual; overload;
+    property Parent : TResourceTreeNode read fParent;
+  public
+    destructor Destroy; override;
+    procedure Add(aResource : TAbstractResource); virtual; abstract;
+    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; virtual; abstract;
+    function CreateResource : TAbstractResource; virtual;
+    procedure Clear;
+    function Remove(aType, aName : TResourceDesc) : TAbstractResource; overload;
+    function Remove(aType, aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
+    function Find(aType, aName : TResourceDesc) : TAbstractResource; overload;
+    function Find(aType, aName : TResourceDesc; const aLangID : TLangID) : TAbstractResource; overload;
+    function FindFreeID(aType : TResourceDesc) : TResID; virtual;
+    function IsLeaf : boolean; virtual;
+    property Desc : TResourceDesc read fDesc;
+    property NamedCount : longword read GetNamedCount;
+    property NamedEntries[index : integer] : TResourceTreeNode read GetNamedEntry;
+    property IDCount : longword read GetIDCount;
+    property IDEntries[index : integer] : TResourceTreeNode read GetIDEntry;
+    property NameRVA : longword read fNameRVA write fNameRVA;
+    property SubDirRVA : longword read fSubDirRVA write fSubDirRVA;
+    property DataRVA : longword read fDataRVA write fDataRVA;
+    property Data : TAbstractResource read GetData;
+  end;
+
+  { TRootResTreeNode }
+
+  TRootResTreeNode = class (TResourceTreeNode)
+  protected
+    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; override;
+  public
+    constructor Create; override;
+    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; override;
+    procedure Add(aResource : TAbstractResource); override;
+    function FindFreeID(aType : TResourceDesc) : TResID; override;
+  end;
+
+implementation
+
+uses resfactory;
+
+  { TTypeResTreeNode }
+
+type
+  TTypeResTreeNode = class (TResourceTreeNode)
+  protected
+    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; override;
+  public
+    constructor Create(aType : TResourceDesc; aParent : TResourceTreeNode); overload;
+    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; override;
+    procedure Add(aResource : TAbstractResource); override;
+    function FindFreeID(aType : TResourceDesc) : TResID; override;
+  end;
+
+  { TNameResTreeNode }
+
+  TNameResTreeNode = class (TResourceTreeNode)
+  protected
+    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; override;
+  public
+    constructor Create(aName : TResourceDesc; aParent : TResourceTreeNode); overload;
+    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; override;
+    procedure Add(aResource : TAbstractResource); override;
+  end;
+
+  { TLangIDResTreeNode }
+
+  TLangIDResTreeNode = class (TResourceTreeNode)
+  private
+    fData : TAbstractResource;
+  protected
+    function GetData : TAbstractResource; override;
+    function InternalFind(aType, aName : TResourceDesc; const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource; override;
+  public
+    constructor Create(aLangID : TLangID; aResource : TAbstractResource; aParent : TResourceTreeNode); overload;
+    function CreateResource : TAbstractResource; override;
+    function CreateSubNode(aDesc : TResourceDesc) : TResourceTreeNode; override;
+    procedure Add(aResource : TAbstractResource); override;
+    function IsLeaf : boolean; override;
+  end;
+
+function CompareDesc(desc1, desc2 : TResourceDesc) : integer;
+begin
+  if desc1.DescType=desc2.DescType then
+  begin
+    case desc1.DescType of
+      dtID : Result:=desc1.ID - desc2.ID;
+      dtName : Result:=CompareStr(desc1.Name,desc2.Name);
+    end;
+  end
+  else
+    case desc1.DescType of
+      dtID : Result:=1;
+      dtName : Result:=-1;
+    end;
+end;
+
+function ResListCompare(Item1: Pointer;Item2: Pointer) : Integer;
+var node1, node2 : TResourceTreeNode;
+begin
+  node1:=TResourceTreeNode(Item1);
+  node2:=TResourceTreeNode(Item2);
+  Result:=CompareDesc(node1.Desc,node2.Desc);
+end;
+
+{ TResourceTreeNode }
+
+function TResourceTreeNode.GetIDEntry(index : integer): TResourceTreeNode;
+begin
+  Result:=TResourceTreeNode(fIDEntries[index]);
+end;
+
+function TResourceTreeNode.GetData: TAbstractResource;
+begin
+  Result:=nil;
+end;
+
+function TResourceTreeNode.InternalFind(aList: TFPList; aDesc: TResourceDesc; out index: integer
+  ): boolean;
+var l, r, p,res : integer;
+begin
+  Result:=true;
+  l:=0;
+  r:=aList.Count-1;
+
+  while l<=r do
+  begin
+    p:=(l+r) div 2;
+    res:=CompareDesc(TResourceTreeNode(aList[p]).Desc, aDesc);
+    if res<0 then l:=p+1
+    else if res>0 then r:=p-1
+    else if res=0 then
+    begin
+      index:=p;
+      exit;
+    end;
+  end;
+  index:=l; //the item can be inserted here
+  Result:=false;
+end;
+
+function TResourceTreeNode.InternalFind(aList: TFPList; aLangID: TLangID; out
+  index: integer): boolean;
+var l, r, p,res : integer;
+begin
+  Result:=true;
+  l:=0;
+  r:=aList.Count-1;
+
+  while l<=r do
+  begin
+    p:=(l+r) div 2;
+    if TResourceTreeNode(aList[p]).Desc.DescType=dtName then res:=-1
+    else res:=TResourceTreeNode(aList[p]).Desc.ID - aLangID;
+    if res<0 then l:=p+1
+    else if res>0 then r:=p-1
+    else if res=0 then
+    begin
+      index:=p;
+      exit;
+    end;
+  end;
+  index:=l; //the item can be inserted here
+  Result:=false;
+end;
+
+function TResourceTreeNode.GetNamedEntry(index : integer): TResourceTreeNode;
+begin
+  Result:=TResourceTreeNode(fNamedEntries[index]);
+end;
+
+function TResourceTreeNode.GetNamedCount: longword;
+begin
+  Result:=fNamedEntries.Count;
+end;
+
+function TResourceTreeNode.GetIDCount: longword;
+begin
+  Result:=fIDEntries.Count;
+end;
+
+constructor TResourceTreeNode.Create;
+begin
+  fDesc:=TResourceDesc.Create(0);
+  fNamedEntries:=TFPList.Create;
+  fIDEntries:=TFPList.Create;
+  fNameRVA:=0;
+  fSubDirRva:=0;
+  fDataRVA:=0;
+  fParent:=nil;
+end;
+
+destructor TResourceTreeNode.Destroy;
+begin
+  fDesc.Free;
+  Clear;
+  fNamedEntries.Free;
+  fIDEntries.Free;
+end;
+
+function TResourceTreeNode.CreateResource: TAbstractResource;
+begin
+  Result:=nil;
+end;
+
+procedure TResourceTreeNode.Clear;
+var i : integer;
+begin
+  for i:=0 to fNamedEntries.Count-1 do
+    TResourceTreeNode(fNamedEntries[i]).Free;
+  for i:=0 to fIDEntries.Count-1 do
+    TResourceTreeNode(fIDEntries[i]).Free;
+  fNamedEntries.Clear;
+  fIDEntries.Clear;
+end;
+
+function TResourceTreeNode.Remove(aType, aName: TResourceDesc
+  ): TAbstractResource;
+begin
+  Result:=InternalFind(aType,aName,0,true,true);
+end;
+
+function TResourceTreeNode.Remove(aType, aName: TResourceDesc;
+  const aLangID: TLangID): TAbstractResource;
+begin
+  Result:=InternalFind(aType,aName,aLangID,false,true);
+end;
+
+function TResourceTreeNode.Find(aType, aName: TResourceDesc
+  ): TAbstractResource;
+begin
+  Result:=InternalFind(aType,aName,0,true,false);
+end;
+
+function TResourceTreeNode.Find(aType, aName: TResourceDesc;
+  const aLangID: TLangID): TAbstractResource;
+begin
+  Result:=InternalFind(aType,aName,aLangID,false,false);
+end;
+
+function TResourceTreeNode.FindFreeID(aType: TResourceDesc): TResID;
+begin
+  Result:=0;
+end;
+
+function TResourceTreeNode.IsLeaf: boolean;
+begin
+  Result:=false;
+end;
+
+{ TRootResTreeNode }
+
+constructor TRootResTreeNode.Create;
+begin
+  inherited Create;
+end;
+
+function TRootResTreeNode.CreateSubNode(aDesc: TResourceDesc
+  ): TResourceTreeNode;
+var theList : TFPList;
+begin
+  case aDesc.DescType of
+    dtID : theList:=fIDEntries;
+    dtName : theList:=fNamedEntries;
+  end;
+  Result:=TTypeResTreeNode.Create(aDesc,self);
+  thelist.Add(Result);
+end;
+
+procedure TRootResTreeNode.Add(aResource: TAbstractResource);
+var theList : TFPList;
+    idx : integer;
+    subitem : TResourceTreeNode;
+begin
+  case aResource._Type.DescType of
+    dtID : theList:=fIDEntries;
+    dtName : theList:=fNamedEntries;
+  end;
+  if InternalFind(theList,aResource._Type,idx) then
+    subitem:=TResourceTreeNode(theList[idx])
+  else
+  begin
+    subitem:=TTypeResTreeNode.Create(aResource._Type,self);
+    theList.Insert(idx,subitem);
+  end;
+  subitem.Add(aResource);
+end;
+
+function TRootResTreeNode.FindFreeID(aType: TResourceDesc): TResID;
+var theList : TFPList;
+    idx : integer;
+    subitem : TResourceTreeNode;
+begin
+  Result:=1;
+  case aType.DescType of
+    dtID : theList:=fIDEntries;
+    dtName : theList:=fNamedEntries;
+  end;
+  if InternalFind(theList,aType,idx) then
+    subitem:=TResourceTreeNode(theList[idx])
+  else exit;
+  Result:=subitem.FindFreeID(aType);
+end;
+
+function TRootResTreeNode.InternalFind(aType, aName : TResourceDesc;
+  const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource;
+var theList : TFPList;
+    idx : integer;
+    subitem : TResourceTreeNode;
+begin
+  Result:=nil;
+  case aType.DescType of
+    dtID : theList:=fIDEntries;
+    dtName : theList:=fNamedEntries;
+  end;
+  if InternalFind(theList,aType,idx) then
+    subitem:=TResourceTreeNode(theList[idx])
+  else exit;
+  Result:=subitem.InternalFind(aType,aName,aLangID,noLangID,toDelete);
+  if toDelete and ((subitem.IDCount+subitem.NamedCount)=0) then
+  begin
+    subitem.Free;
+    theList.Delete(idx);
+  end;
+end;
+
+{ TTypeResTreeNode }
+
+constructor TTypeResTreeNode.Create(aType: TResourceDesc;
+  aParent: TResourceTreeNode);
+begin
+  inherited Create;
+  fDesc.Assign(aType);
+  fParent:=aParent;
+end;
+
+function TTypeResTreeNode.CreateSubNode(aDesc: TResourceDesc
+  ): TResourceTreeNode;
+var theList : TFPList;
+begin
+  case aDesc.DescType of
+    dtID : theList:=fIDEntries;
+    dtName : theList:=fNamedEntries;
+  end;
+  Result:=TNameResTreeNode.Create(aDesc,self);
+  thelist.Add(Result);
+end;
+
+procedure TTypeResTreeNode.Add(aResource: TAbstractResource);
+var theList : TFPList;
+    idx : integer;
+    subitem : TResourceTreeNode;
+begin
+  case aResource.Name.DescType of
+    dtID : theList:=fIDEntries;
+    dtName : theList:=fNamedEntries;
+  end;
+  if InternalFind(theList,aResource.Name,idx) then
+    subitem:=TResourceTreeNode(theList[idx])
+  else
+  begin
+    subitem:=TNameResTreeNode.Create(aResource.Name,self);
+    theList.Insert(idx,subitem);
+  end;
+  subitem.Add(aResource);
+end;
+
+function TTypeResTreeNode.FindFreeID(aType: TResourceDesc): TResID;
+var i : integer;
+begin
+  Result:=1;
+  if IDCount<=0 then exit; //no items, use 1
+  Result:=IDEntries[IDCount-1].Desc.ID+1; //try last one+1
+  if Result>$FFFF then
+    if IDEntries[0].Desc.ID>1 then Result:=IDEntries[0].Desc.ID-1 //try first one-1
+    else
+    begin //scan the whole list to find the first free id.
+      Result:=1;
+      for i:=0 to IDCount-1 do
+      begin
+        if IDEntries[i].Desc.ID<>Result then exit;
+        inc(Result);
+      end;
+      raise ENoMoreFreeIDsException.Create('');
+    end;
+end;
+
+function TTypeResTreeNode.InternalFind(aType, aName : TResourceDesc;
+  const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource;
+var theList : TFPList;
+    idx : integer;
+    subitem : TResourceTreeNode;
+begin
+  Result:=nil;
+  case aName.DescType of
+    dtID : theList:=fIDEntries;
+    dtName : theList:=fNamedEntries;
+  end;
+  if InternalFind(theList,aName,idx) then
+    subitem:=TResourceTreeNode(theList[idx])
+  else exit;
+  Result:=subitem.InternalFind(aType,aName,aLangID,noLangID,toDelete);
+  if toDelete and ((subitem.IDCount+subitem.NamedCount)=0) then
+  begin
+    subitem.Free;
+    theList.Delete(idx);
+  end;
+end;
+
+{ TNameResTreeNode }
+
+constructor TNameResTreeNode.Create(aName: TResourceDesc;
+  aParent: TResourceTreeNode);
+begin
+  inherited Create;
+  fDesc.Assign(aName);
+  fParent:=aParent;
+end;
+
+function TNameResTreeNode.CreateSubNode(aDesc: TResourceDesc
+  ): TResourceTreeNode;
+var theList : TFPList;
+begin
+  case aDesc.DescType of
+    dtID : theList:=fIDEntries;
+    dtName : theList:=fNamedEntries;
+  end;
+  Result:=TLangIDResTreeNode.Create(aDesc.ID,nil,self);
+  thelist.Add(Result);
+end;
+
+procedure TNameResTreeNode.Add(aResource: TAbstractResource);
+var idx : integer;
+    subitem : TResourceTreeNode;
+begin
+  if InternalFind(fIDEntries,aResource.LangID,idx) then
+    raise EResourceDuplicateException.Create('');
+
+  subitem:=TLangIDResTreeNode.Create(aResource.LangID,aResource,self);
+  fIDEntries.Insert(idx,subitem);
+end;
+
+function TNameResTreeNode.InternalFind(aType, aName : TResourceDesc;
+  const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource;
+var idx : integer;
+begin
+  Result:=nil;
+  if noLangID then
+  begin
+    if IDCount<=0 then exit
+    else idx:=0;
+  end
+  else
+  if not InternalFind(fIDEntries,aLangID,idx) then exit;
+
+  Result:=IDEntries[idx].Data;
+  if toDelete then
+  begin
+    IDEntries[idx].Free;
+    fIDEntries.Delete(idx);
+  end;
+end;
+
+{ TLangIDResTreeNode }
+
+function TLangIDResTreeNode.GetData: TAbstractResource;
+begin
+  Result:=fData;
+end;
+
+constructor TLangIDResTreeNode.Create(aLangID: TLangID;
+  aResource: TAbstractResource; aParent: TResourceTreeNode);
+begin
+  inherited Create;
+  fDesc.ID:=aLangID;
+  fData:=aResource;
+  fParent:=aParent;
+end;
+
+function TLangIDResTreeNode.CreateResource: TAbstractResource;
+var theType, theName : TResourceDesc;
+begin
+  Result:=nil;
+  if fData<>nil then exit;
+  theType:=Parent.Parent.Desc;
+  theName:=Parent.Desc;
+  fData:=TResourceFactory.CreateResource(theType,theName);
+  fData.LangID:=fDesc.ID;
+  Result:=fData;
+end;
+
+function TLangIDResTreeNode.CreateSubNode(aDesc: TResourceDesc
+  ): TResourceTreeNode;
+begin
+  Result:=nil;
+end;
+
+procedure TLangIDResTreeNode.Add(aResource: TAbstractResource);
+begin
+  //can't add, it's a leaf node
+end;
+
+function TLangIDResTreeNode.InternalFind(aType, aName : TResourceDesc;
+  const aLangID : TLangID; const noLangID,toDelete : boolean) : TAbstractResource;
+begin
+  //can't find, it's a leaf node
+  Result:=nil;
+end;
+
+function TLangIDResTreeNode.IsLeaf: boolean;
+begin
+  Result:=true;
+end;
+
+end.

+ 260 - 0
packages/fcl-res/src/resreader.pp

@@ -0,0 +1,260 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for .res files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit resreader;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+
+type
+
+  { TResResourceReader }
+
+  TResResourceReader = class (TAbstractResourceReader)
+  private
+    fExtensions : string;
+    fDescription : string;
+    dummyType : TResourceDesc;
+    dummyName : TResourceDesc;
+    procedure AlignDword(aStream : TStream);
+    function ReadResourceHeader(aStream : TStream) : TAbstractResource;
+    function ReadUnicodeString(aStream : TStream; maxsize : integer; out count : integer) : widestring;
+    function ReadNameID(aStream : TStream; aDesc : TResourceDesc ;maxsize : integer) : integer;
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Load(aResources : TResources; aStream : TStream); override;
+    function CheckMagic(aStream : TStream) : boolean; override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+  end;
+
+
+implementation
+
+uses resdatastream, resfactory;
+
+//This exception is raised when end of stream is detected and expected,
+//that is, before reading a new resource header. It's not an error.
+type
+  EResourceReaderEOSReachedException = class (EResourceReaderException);
+
+
+{ TResResourceReader }
+
+procedure TResResourceReader.AlignDword(aStream: TStream);
+var toskip : integer;
+begin
+  toskip:=4-(aStream.Position mod 4);
+  if toskip<>4 then aStream.Seek(toskip,soFromCurrent);
+end;
+
+function TResResourceReader.ReadResourceHeader(aStream: TStream
+  ): TAbstractResource;
+var DataSize : longword;
+    HeaderSize : longword;
+    toread : longword;
+    DataVersion : longword;
+    MemoryFlags : word;
+    LanguageID : word;
+    Version : longword;
+    Characteristics : longword;
+    DataOffset : longword;
+    RawData : TResourceDataStream;
+begin
+  try
+    aStream.ReadBuffer(DataSize,4);
+  except
+    on e : EReadError do
+      raise EResourceReaderEOSReachedException.Create('');
+  end;
+  try
+    aStream.ReadBuffer(HeaderSize,4);
+    {$IFDEF ENDIAN_BIG}
+    DataSize:=SwapEndian(DataSize);
+    HeaderSize:=SwapEndian(HeaderSize);
+    {$ENDIF}
+    toread:=headersize-8;
+    toread:=toread-ReadNameID(aStream,dummyType,toread-18);
+    toread:=toread-ReadNameID(aStream,dummyName,toread-16);
+    AlignDword(aStream);
+    aStream.ReadBuffer(DataVersion,4);
+    aStream.ReadBuffer(MemoryFlags,2);
+    aStream.ReadBuffer(LanguageID,2);
+    aStream.ReadBuffer(Version,4);
+    aStream.ReadBuffer(Characteristics,4);
+    {$IFDEF ENDIAN_BIG}
+    DataVersion:=SwapEndian(DataVersion);
+    MemoryFlags:=SwapEndian(MemoryFlags);
+    LanguageID:=SwapEndian(LanguageID);
+    Version:=SwapEndian(Version);
+    Characteristics:=SwapEndian(Characteristics);
+    {$ENDIF}
+    DataOffset:=aStream.Position;
+
+    Result:=TResourceFactory.CreateResource(dummyType,dummyName);
+    SetDataSize(Result,DataSize);
+    SetHeaderSize(Result,HeaderSize);
+    Result.DataVersion:=DataVersion;
+    Result.MemoryFlags:=MemoryFlags;
+    Result.LangID:=LanguageID;
+    Result.Version:=Version;
+    Result.Characteristics:=Characteristics;
+    SetDataOffset(Result,DataOffset);
+    RawData:=TResourceDataStream.Create(aStream,Result,Result.DataSize,TCachedResourceDataStream);
+    SetRawData(Result,RawData);
+    if DataSize>0 then
+    begin
+      aStream.Seek(DataSize,soFromCurrent);
+      AlignDword(aStream);
+    end;
+  except
+    on e : EReadError do
+      raise EResourceReaderUnexpectedEndOfStreamException.Create('');
+  end;
+end;
+
+function TResResourceReader.ReadUnicodeString(aStream: TStream; maxsize: integer;
+   out count : integer): widestring;
+var w : word;
+begin
+  Result:='';
+  w:=0;
+  count:=0;
+  repeat
+    aStream.ReadBuffer(w,2);
+    if w<>0 then
+    begin
+      {$IFDEF ENDIAN_BIG}
+      w:=SwapEndian(w);
+      {$ENDIF}
+      Result:=Result+widechar(w);
+    end;
+    dec(maxsize);
+    inc(count);
+  until (w=0) or (maxsize<=0);
+  count:=count*2;
+end;
+
+function TResResourceReader.ReadNameID(aStream : TStream; aDesc : TResourceDesc;
+  maxsize : integer) : integer;
+var tmpw : word;
+    ws : widestring;
+begin
+  aStream.ReadBuffer(tmpw,2);
+  {$IFDEF ENDIAN_BIG}
+  tmpw:=SwapEndian(tmpw);
+  {$ENDIF}
+  if tmpw = $FFFF then
+  begin
+    aStream.ReadBuffer(tmpw,2);
+    {$IFDEF ENDIAN_BIG}
+    tmpw:=SwapEndian(tmpw);
+    {$ENDIF}
+    aDesc.ID:=tmpw;
+    Result:=4;
+  end
+  else
+  begin
+    ws:=widechar(tmpw)+ReadUnicodeString(aStream,maxsize,Result);
+    aDesc.Name:=ws;
+    inc(Result,2);
+  end;
+end;
+
+function TResResourceReader.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TResResourceReader.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TResResourceReader.Load(aResources: TResources; aStream: TStream);
+var aRes : TAbstractResource;
+begin
+  if not CheckMagic(aStream) then
+    raise EResourceReaderWrongFormatException.Create('');
+  try
+    while true do
+    begin
+      aRes:=ReadResourceHeader(aStream);
+      try
+        aResources.Add(aRes);
+      except
+        on e : EResourceDuplicateException do
+        begin
+          aRes.Free;
+          raise;
+        end;
+      end;
+    end;
+  except
+    on e : EResourceReaderEOSReachedException do ;
+  end;
+end;
+
+function TResResourceReader.CheckMagic(aStream: TStream): boolean;
+var lw : longword;
+begin
+  Result:=false;
+  aStream.ReadBuffer(lw,4); if lw<>0 then exit; //datasize = 0
+  aStream.ReadBuffer(lw,4);
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  if lw<>$20 then exit;                         //headersize = $20
+  aStream.ReadBuffer(lw,4);
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  if lw<>$FFFF then exit;                       //type = $0000FFFF
+  aStream.ReadBuffer(lw,4);
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  if lw<>$FFFF then exit;                       //name = $0000FFFF
+  aStream.ReadBuffer(lw,4); if lw<>0 then exit; //dataversion = 0
+  aStream.ReadBuffer(lw,4); if lw<>0 then exit; //memflags,langid = 0
+  aStream.ReadBuffer(lw,4); if lw<>0 then exit; //version = 0
+  aStream.ReadBuffer(lw,4); if lw<>0 then exit; //characteristics = 0
+  Result:=true;
+end;
+
+constructor TResResourceReader.Create;
+begin
+  fExtensions:='.res';
+  fDescription:='.res resource reader';
+  dummyType:=TResourceDesc.Create;
+  dummyName:=TResourceDesc.Create;
+end;
+
+destructor TResResourceReader.Destroy;
+begin
+  dummyType.Free;
+  dummyName.Free;
+end;
+
+initialization
+  TResources.RegisterReader('.res',TResResourceReader);
+
+end.

+ 199 - 0
packages/fcl-res/src/reswriter.pp

@@ -0,0 +1,199 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource writer for .res files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit reswriter;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+  
+type
+
+  { TResResourceWriter }
+
+  TResResourceWriter = class (TAbstractResourceWriter)
+  private
+    fExtensions : string;
+    fDescription : string;
+    procedure AlignDword(aStream : TStream);
+    procedure WriteFileHeader(aStream : TStream);
+    procedure WriteResource(aStream : TStream; aRes : TAbstractResource);
+    procedure WriteNameId(aStream : TStream; aDesc : TResourceDesc);
+    procedure WriteUnicodeString(aStream : TStream; const aName : string);
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Write(aResources : TResources; aStream : TStream); override;
+  public
+    constructor Create; override;
+  end;
+
+implementation
+
+{ TResResourceWriter }
+
+procedure TResResourceWriter.AlignDword(aStream: TStream);
+var topad : integer;
+    lw : longword;
+begin
+  lw:=0;
+  topad:=4-(aStream.Position mod 4);
+  if topad<>4 then aStream.WriteBuffer(lw,topad);
+end;
+
+procedure TResResourceWriter.WriteFileHeader(aStream: TStream);
+var lw : longword;
+begin
+  lw:=0; aStream.WriteBuffer(lw,4);             //datasize = 0
+  lw:=$20;
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  aStream.WriteBuffer(lw,4);                    //headersize = $20
+  lw:=$FFFF;
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  aStream.WriteBuffer(lw,4);                    //type = $0000FFFF
+  aStream.WriteBuffer(lw,4);                    //name = $0000FFFF
+  lw:=0;
+  aStream.WriteBuffer(lw,4);                    //dataversion = 0
+  aStream.WriteBuffer(lw,4);                    //memflags,langid = 0
+  aStream.WriteBuffer(lw,4);                    //version = 0
+  aStream.WriteBuffer(lw,4);                    //characteristics = 0
+end;
+
+procedure TResResourceWriter.WriteResource(aStream: TStream;
+  aRes: TAbstractResource);
+var lw : longword;
+    DataVersion : longword;
+    MemoryFlags : word;
+    LanguageID : word;
+    Version : longword;
+    Characteristics : longword;
+    posbefore, posafter : int64;
+begin
+  AlignDword(aStream);
+  posbefore:=aStream.Position;
+  lw:=aRes.DataSize;
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  aStream.WriteBuffer(lw,4);                  //datasize
+  aStream.WriteBuffer(lw,4);                  //headersize - to be filled later
+  WriteNameId(aStream,aRes._Type);            //type
+  WriteNameId(aStream,aRes.Name);             //name
+  AlignDword(aStream);
+  
+  DataVersion:=aRes.DataVersion;
+  MemoryFlags:=aRes.MemoryFlags;
+  LanguageID:=aRes.LangID;
+  Version:=aRes.Version;
+  Characteristics:=aRes.Characteristics;
+  {$IFDEF ENDIAN_BIG}
+  DataVersion:=SwapEndian(DataVersion);
+  MemoryFlags:=SwapEndian(MemoryFlags);
+  LanguageID:=SwapEndian(LanguageID);
+  Version:=SwapEndian(Version);
+  Characteristics:=SwapEndian(Characteristics);
+  {$ENDIF}
+  aStream.WriteBuffer(DataVersion,4);         //dataversion
+  aStream.WriteBuffer(MemoryFlags,2);         //memoryflags
+  aStream.WriteBuffer(LanguageID,2);          //language id
+  aStream.WriteBuffer(Version,4);             //version
+  aStream.WriteBuffer(Characteristics,4);     //characteristics
+  posafter:=aStream.Position;
+  lw:=posafter-posbefore;
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  aStream.Position:=posbefore+4;
+  aStream.WriteBuffer(lw,4);                  //fix header size
+  aStream.Position:=posafter;
+
+  //copy resource data
+  aRes.RawData.Position:=0;
+  aStream.CopyFrom(aRes.RawData,aRes.DataSize);
+end;
+
+procedure TResResourceWriter.WriteNameId(aStream: TStream; aDesc: TResourceDesc
+  );
+var w1,w2 : word;
+begin
+  case aDesc.DescType of
+    dtID :
+      begin
+        w1:=$FFFF;
+        w2:=aDesc.ID;
+        {$IFDEF ENDIAN_BIG}
+        w2:=SwapEndian(w2);
+        {$ENDIF}
+        aStream.WriteBuffer(w1,2);
+        aStream.WriteBuffer(w2,2);
+      end;
+    dtName : WriteUnicodeString(aStream,aDesc.Name);
+  end;
+end;
+
+procedure TResResourceWriter.WriteUnicodeString(aStream: TStream;
+  const aName: string);
+var ws : widestring;
+    w : word;
+    i : integer;
+begin
+  ws:=aName;
+  for i:=1 to length(ws) do
+  begin
+    w:=word(ws[i]);
+    {$IFDEF ENDIAN_BIG}
+    w:=SwapEndian(w);
+    {$ENDIF}
+    aStream.WriteBuffer(w,2);
+  end;
+  w:=0;
+  aStream.WriteBuffer(w,2);
+end;
+
+function TResResourceWriter.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TResResourceWriter.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TResResourceWriter.Write(aResources: TResources; aStream: TStream);
+var i : integer;
+begin
+  WriteFileHeader(aStream);
+  for i:=0 to aResources.Count-1 do
+    WriteResource(aStream,aResources[i]);
+end;
+
+constructor TResResourceWriter.Create;
+begin
+  fExtensions:='.res';
+  fDescription:='.res resource writer';
+end;
+
+initialization
+  TResources.RegisterWriter('.res',TResResourceWriter);
+
+end.

+ 259 - 0
packages/fcl-res/src/stringtableresource.pp

@@ -0,0 +1,259 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    String table resource type
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit stringtableresource;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+  
+type
+  EStringTableResourceException = class(EResourceException);
+  EStringTableNameNotAllowedException = class(EStringTableResourceException);
+  EStringTableIndexOutOfBoundsException = class(EStringTableResourceException);
+
+  
+resourcestring
+  SNameNotAllowed = 'Resource ID must be an ordinal in the range 1-4096';
+  SIndexOutOfBounds = 'String ID out of bounds: %d';
+
+type
+
+  { TStringTableResource }
+
+  TStringTableResource = class(TAbstractResource)
+  private
+    fType : TResourceDesc;
+    fName : TResourceDesc;
+    fFirstID : word;
+    fCount : integer;
+    fList : TStringList;
+    fCanChangeDesc : boolean;
+    function IDtoIndex(const aId : word) : integer;
+    procedure CheckListLoaded;
+    function ReadWideString : string;
+    procedure WriteWideString(const aString : string);
+    function GetLastID : word;
+    procedure SetFirstID(aId : word);
+    function GetString(id : word) : string;
+    procedure SetString(id : word; aString : string);
+    procedure CheckIndex(const aIndex : word);
+  protected
+    function GetType : TResourceDesc; override;
+    function GetName : TResourceDesc; override;
+    function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
+    function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
+    procedure NotifyResourcesLoaded; override;
+  public
+    constructor Create; override;
+    constructor Create(aType,aName : TResourceDesc); override;
+    destructor Destroy; override;
+    procedure UpdateRawData; override;
+    property FirstID : word read fFirstID write SetFirstID;
+    property LastID : word read GetLastID;
+    property Count : integer read fCount;
+    property Strings[id : word] : string read GetString write SetString; default;
+  end;
+
+implementation
+
+uses
+  resfactory;
+
+{ TStringTableResource }
+
+function TStringTableResource.IDtoIndex(const aId: word): integer;
+begin
+  Result:=aID-fFirstID;
+end;
+
+procedure TStringTableResource.CheckListLoaded;
+var i : integer;
+begin
+  if fList<>nil then exit;
+  fList:=TStringList.Create;
+  fList.Capacity:=16;
+  if RawData.Size=0 then exit;
+  RawData.Position:=0;
+  for i:=0 to 15 do
+    fList.Add(ReadWideString);
+end;
+
+function TStringTableResource.ReadWideString: string;
+var ws : widestring;
+    w : word;
+    i : integer;
+begin
+  RawData.ReadBuffer(w,2);
+  {$IFDEF ENDIAN_BIG}
+  w:=SwapEndian(w);
+  {$ENDIF}
+  setlength(ws,w);
+
+  for i:=1 to length(ws) do
+  begin
+    RawData.ReadBuffer(w,2);
+    {$IFDEF ENDIAN_BIG}
+    w:=SwapEndian(w);
+    {$ENDIF}
+    ws[i]:=widechar(w);
+  end;
+  Result:=ws;
+end;
+
+procedure TStringTableResource.WriteWideString(const aString: string);
+var ws : widestring;
+    w : word;
+    i : integer;
+begin
+  w:=length(aString);
+  {$IFDEF ENDIAN_BIG}
+  w:=SwapEndian(w);
+  {$ENDIF}
+  RawData.WriteBuffer(w,2);
+  ws:=aString;
+  for i:=1 to length(ws) do
+  begin
+    w:=word(ws[i]);
+    {$IFDEF ENDIAN_BIG}
+    w:=SwapEndian(w);
+    {$ENDIF}
+    RawData.WriteBuffer(w,2);
+  end;
+end;
+
+function TStringTableResource.GetLastID: word;
+begin
+  Result:=fFirstID+15;
+end;
+
+procedure TStringTableResource.SetFirstID(aId: word);
+begin
+  aId:=aID and $FFF0;
+  fFirstID:=aID;
+  fCanChangeDesc:=true;
+  fName.ID:=(aID div 16)+1;
+  fCanChangeDesc:=false;
+end;
+
+function TStringTableResource.GetString(id: word): string;
+var idx : integer;
+begin
+  CheckIndex(id);
+  CheckListLoaded;
+  idx:=IDtoIndex(id);
+  if idx>=fList.Count then Result:=''
+  else Result:=fList[idx];
+end;
+
+procedure TStringTableResource.SetString(id: word; aString: string);
+var idx,i : integer;
+begin
+  CheckIndex(id);
+  CheckListLoaded;
+  idx:=IDtoIndex(id);
+  if idx<fList.Count then fList[idx]:=aString
+  else if idx>=fList.Count then
+  begin
+    for i:=fList.Count to idx-1 do
+      fList.Add('');
+    fList.Add(aString);
+  end;
+end;
+
+procedure TStringTableResource.UpdateRawData;
+var i : integer;
+begin
+  if fList=nil then exit;
+  RawData.Size:=0;
+  RawData.Position:=0;
+  for i:=FirstID to LastID do
+    WriteWideString(Strings[i]);
+  FreeAndNil(fList);
+end;
+
+function TStringTableResource.GetType: TResourceDesc;
+begin
+  Result:=fType;
+end;
+
+function TStringTableResource.GetName: TResourceDesc;
+begin
+  Result:=fName;
+end;
+
+function TStringTableResource.ChangeDescTypeAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=fCanChangeDesc;
+end;
+
+function TStringTableResource.ChangeDescValueAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=fCanChangeDesc;
+end;
+
+procedure TStringTableResource.NotifyResourcesLoaded;
+begin
+end;
+
+procedure TStringTableResource.CheckIndex(const aIndex: word);
+begin
+  if (aIndex<FirstID) or (aIndex>LastID) then
+    raise EStringTableIndexOutOfBoundsException.CreateFmt(SIndexOutOfBounds,[aIndex])
+end;
+
+constructor TStringTableResource.Create;
+begin
+  inherited Create;
+  fCanChangeDesc:=false;
+  fList:=nil;
+  fType:=TResourceDesc.Create(RT_STRING);
+  fName:=TResourceDesc.Create(1);
+  fCount:=16;
+  fFirstID:=0;
+  SetDescOwner(fType);
+  SetDescOwner(fName);
+end;
+
+constructor TStringTableResource.Create(aType, aName: TResourceDesc);
+begin
+  Create;
+  if (aName.DescType<>dtId) or ((aName.ID <1) or  (aName.ID >4096)) then
+    raise EStringTableNameNotAllowedException.Create(SNameNotAllowed);
+  fCanChangeDesc:=true;
+  fName.Assign(aName);
+  fCanChangeDesc:=false;
+  fCount:=16;
+  fFirstID:=(fName.ID-1) * 16;
+end;
+
+destructor TStringTableResource.Destroy;
+begin
+  fType.Free;
+  fName.Free;
+  if fList<>nil then
+    fList.Free;
+  inherited Destroy;
+end;
+
+initialization
+  TResourceFactory.RegisterResourceClass(RT_STRING,TStringTableResource);
+
+end.

+ 185 - 0
packages/fcl-res/src/strtable.pp

@@ -0,0 +1,185 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    String table classes used internally by readers and writers
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit strtable;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes;
+
+type
+
+  { TResStringTable }
+
+  TResStringTable = class
+  private
+    fStartOfs : longword;
+    fData : TMemoryStream;
+    fUsed : boolean;
+    function GetSize : longword;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function Add(s : string) : longword;
+    procedure Clear;
+    procedure WriteToStream(aStream : TStream);
+    property StartOfs : longword read fStartOfs write fStartOfs;
+    property Size : longword read GetSize;
+    property Used : boolean read fUsed;
+  end;
+  
+  { TObjectStringTable }
+
+  TObjectStringTable = class
+  private
+    fData : TMemoryStream;
+    fStartOfs : longword;
+    function GetSize : longword;
+  protected
+  public
+    constructor Create(aStream : TStream; aSize : longword);
+    destructor Destroy; override;
+    function Get(aOffset : longword) : string;
+    function Add(aString : string) : longword;
+    procedure Clear;
+    procedure WriteToStream(aStream : TStream);
+    property Size : longword read GetSize;
+    property StartOfs : longword read fStartOfs write fStartOfs;
+  end;
+
+implementation
+
+{ TResStringTable }
+
+function TResStringTable.GetSize: longword;
+begin
+  Result:=fData.Size;
+end;
+
+constructor TResStringTable.Create;
+var b : byte;
+begin
+  fStartOfs:=0;
+  fData:=TMemoryStream.Create;
+  b:=0;
+  fData.WriteBuffer(b,1);
+  fUsed:=false;
+end;
+
+destructor TResStringTable.Destroy;
+begin
+  fData.Free;
+end;
+
+function TResStringTable.Add(s: string): longword;
+var b : byte;
+begin
+  fUsed:=true;
+  Result:=fData.Position;
+  if s='' then Result:=0
+  else
+  begin
+    fData.WriteBuffer(s[1],length(s));
+    b:=0;
+    fData.WriteBuffer(b,1);
+  end;
+end;
+
+procedure TResStringTable.Clear;
+begin
+  fStartOfs:=0;
+  fData.SetSize(1);
+  fData.Position:=1;
+  fUsed:=false;
+end;
+
+procedure TResStringTable.WriteToStream(aStream: TStream);
+var oldpos : int64;
+begin
+  oldpos:=fData.Position;
+  try
+    fData.Position:=0;
+    aStream.CopyFrom(fData,fData.Size);
+  finally
+    fData.Position:=oldpos;
+  end;
+end;
+
+{ TObjectStringTable }
+
+function TObjectStringTable.GetSize: longword;
+begin
+  Result:=fData.Size;
+end;
+
+constructor TObjectStringTable.Create(aStream: TStream; aSize: longword);
+var b : byte;
+begin
+  fData:=TMemoryStream.Create;
+  fData.Position:=0;
+  if aStream=nil then
+  begin
+    b:=0;
+    fData.WriteBuffer(b,1);
+  end
+  else
+    fData.CopyFrom(aStream,aSize);
+end;
+
+destructor TObjectStringTable.Destroy;
+begin
+  fData.Free;
+end;
+
+function TObjectStringTable.Get(aOffset: longword): string;
+var c : char;
+begin
+  Result:='';
+  fData.Position:=aOffset;
+  repeat
+    fData.ReadBuffer(c,1);
+    if c<>#0 then Result:=Result+c;
+  until (c=#0) or (fData.Position>=fData.Size);
+end;
+
+function TObjectStringTable.Add(aString: string) : longword;
+var b : byte;
+begin
+  Result:=fData.Position;
+  if aString='' then Result:=0
+  else
+  begin
+    fData.WriteBuffer(aString[1],length(aString));
+    b:=0;
+    fData.WriteBuffer(b,1);
+  end;
+end;
+
+procedure TObjectStringTable.Clear;
+begin
+  fData.SetSize(1);
+  fData.Position:=1;
+end;
+
+procedure TObjectStringTable.WriteToStream(aStream: TStream);
+begin
+  fData.Position:=0;
+  aStream.CopyFrom(fData,fData.Size);
+end;
+
+end.

+ 75 - 0
packages/fcl-res/src/versionconsts.pp

@@ -0,0 +1,75 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Constants used by version information resource
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit versionconsts;
+
+{$MODE OBJFPC}
+
+interface
+
+const
+//FileFlags
+  VS_FF_DEBUG           = $00000001;
+  VS_FF_PRERELEASE      = $00000002;
+  VS_FF_PATCHED         = $00000004;
+  VS_FF_PRIVATEBUILD    = $00000008;
+  VS_FF_INFOINFERRED    = $00000010;
+  VS_FF_SPECIALBUILD    = $00000020;
+  VS_FFI_FILEFLAGSMASK  = $0000003F;
+//FileOS
+  VOS_UNKNOWN           = $00000000;
+  VOS_DOS               = $00010000;
+  VOS_OS216             = $00020000;
+  VOS_OS232             = $00030000;
+  VOS_NT                = $00040000;
+  VOS__BASE             = $00000000;
+  VOS__WINDOWS16        = $00000001;
+  VOS__PM16             = $00000002;
+  VOS__PM32             = $00000003;
+  VOS__WINDOWS32        = $00000004;
+  VOS_DOS_WINDOWS16     = $00010001;
+  VOS_DOS_WINDOWS32     = $00010004;
+  VOS_OS216_PM16        = $00020002;
+  VOS_OS232_PM32        = $00030003;
+  VOS_NT_WINDOWS32      = $00040004;
+//FileType
+  VFT_UNKNOWN           = $00000000;
+  VFT_APP               = $00000001;
+  VFT_DLL               = $00000002;
+  VFT_DRV               = $00000003;
+  VFT_FONT              = $00000004;
+  VFT_VXD               = $00000005;
+  VFT_STATIC_LIB        = $00000007;
+//FileSubType - VFT_DRV
+  VFT2_UNKNOWN          = $00000000;
+  VFT2_DRV_PRINTER      = $00000001;
+  VFT2_DRV_KEYBOARD     = $00000002;
+  VFT2_DRV_LANGUAGE     = $00000003;
+  VFT2_DRV_DISPLAY      = $00000004;
+  VFT2_DRV_MOUSE        = $00000005;
+  VFT2_DRV_NETWORK      = $00000006;
+  VFT2_DRV_SYSTEM       = $00000007;
+  VFT2_DRV_INSTALLABLE  = $00000008;
+  VFT2_DRV_SOUND        = $00000009;
+  VFT2_DRV_COMM         = $0000000A;
+//VFT2_DRV_VERSIONED_PRINTER = ????
+//FileSubType - VFT_FONT
+  VFT2_FONT_RASTER      = $00000001;
+  VFT2_FONT_VECTOR      = $00000002;
+  VFT2_FONT_TRUETYPE    = $00000003;
+
+implementation
+
+end.

+ 592 - 0
packages/fcl-res/src/versionresource.pp

@@ -0,0 +1,592 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Version information resource type
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit versionresource;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  SysUtils, Classes, resource, versiontypes;
+
+type
+  TVerBlockHeader = packed record
+    length    : word;
+    vallength : word;
+    valtype   : word;
+    key       : string;
+  end;
+
+type
+
+  { TVersionResource }
+
+  TVersionResource = class(TAbstractResource)
+  private
+    fType : TResourceDesc;
+    fName : TResourceDesc;
+    fFixedInfo : TVersionFixedInfo;
+    fStringFileInfo : TVersionStringFileInfo;
+    fVarFileInfo : TVersionVarFileInfo;
+    function SwapVersion(const aData : qword) : qword;
+    procedure AlignDWordReading;
+    procedure AlignDWordWriting;
+    function GetFileInfo : TVersionStringFileInfo;
+    function GetFixedInfo : TVersionFixedInfo;
+    function GetVarInfo : TVersionVarFileInfo;
+    procedure CheckDataLoaded;
+    procedure LoadData;
+    procedure LoadFixedInfos;
+    function ReadBlockHeader(out aBlock : TVerBlockHeader) : integer;
+    function ReadStringFileInfo(toread : integer) : integer;
+    function ReadVarFileInfo(toread : integer) : integer;
+    function ReadStringTable(toread : integer;aName : string) : integer;
+    function ReadWideString: string;
+    procedure WriteFixedBlockLength(const position : int64);
+    procedure WriteData;
+    procedure WriteFixedInfos;
+    procedure WriteStringFileInfo;
+    procedure WriteStringTable(aTable : TVersionStringTable);
+    procedure WriteStringEntry(const aKey, aValue : string);
+    procedure WriteVarFileInfo;
+    procedure WriteVarEntry(aEntry : TVerTranslationInfo);
+    procedure WriteWideString(const aString : string);
+  protected
+    function GetType : TResourceDesc; override;
+    function GetName : TResourceDesc; override;
+    function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
+    function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
+    procedure NotifyResourcesLoaded; override;
+  public
+    constructor Create; override;
+    constructor Create(aType,aName : TResourceDesc); override;
+    destructor Destroy; override;
+    procedure UpdateRawData; override;
+    property FixedInfo : TVersionFixedInfo read GetFixedInfo;
+    property StringFileInfo : TVersionStringFileInfo read GetFileInfo;
+    property VarFileInfo : TVersionVarFileInfo read GetVarInfo;
+  end;
+
+
+implementation
+
+uses
+  resfactory;
+  
+type
+  TVSFixedFileInfo = packed record
+    signature : longword;
+    verMinor  : word;
+    verMajor  : word;
+    FileVersion : qword;
+    ProductVersion : qword;
+    FileFlagsMask : longword;
+    FileFlags     : longword;
+    FileOS        : longword;
+    FileType      : longword;
+    FileSubType   : longword;
+    FileDate      : qword;
+  end;
+
+
+{ TVersionResource }
+
+function TVersionResource.SwapVersion(const aData: qword): qword;
+begin
+  {$IFDEF ENDIAN_BIG}
+  Result:=Swap(aData);                      //MSLW is stored first...
+  Result:=SwapEndian(Result);
+  {$ELSE}
+  Result:=Swap(longword(hi(aData)));
+  Result:=Result shl 32;
+  Result:=Result or Swap(longword(lo(aData)));
+  {$ENDIF}
+end;
+
+procedure TVersionResource.AlignDWordReading;
+var toskip : integer;
+begin
+  toskip:=4-(RawData.Position mod 4);
+  if toskip<>4 then RawData.Seek(toskip,soFromCurrent);
+end;
+
+procedure TVersionResource.AlignDWordWriting;
+var topad : integer;
+    lw : longword;
+begin
+  lw:=0;
+  topad:=4-(RawData.Position mod 4);
+  if topad<>4 then RawData.WriteBuffer(lw,topad);
+end;
+
+function TVersionResource.GetFileInfo: TVersionStringFileInfo;
+begin
+  CheckDataLoaded;
+  Result:=fStringFileInfo;
+end;
+
+function TVersionResource.GetFixedInfo: TVersionFixedInfo;
+begin
+  CheckDataLoaded;
+  Result:=fFixedInfo;
+end;
+
+function TVersionResource.GetVarInfo: TVersionVarFileInfo;
+begin
+  CheckDataLoaded;
+  Result:=fVarFileInfo;
+end;
+
+procedure TVersionResource.CheckDataLoaded;
+begin
+  if fFixedInfo<>nil then exit;
+  //if we have no data stream, create empty structures
+  if RawData.Size=0 then
+  begin
+    fFixedInfo:=TVersionFixedInfo.Create;
+    fStringFileInfo:=TVersionStringFileInfo.Create;
+    fVarFileInfo:=TVersionVarFileInfo.Create;
+  end
+  else LoadData;
+end;
+
+procedure TVersionResource.LoadData;
+var tmp : integer;
+    toread : word;
+    block : TVerBlockHeader;
+    i : integer;
+begin
+  RawData.Position:=0;
+  tmp:=ReadBlockHeader(block);
+                                        //block.key should be 'VS_VERSION_INFO'
+  toread:=block.length;
+  LoadFixedInfos;
+  AlignDWordReading;
+  dec(toread,RawData.Position);
+  
+  fStringFileInfo:=TVersionStringFileInfo.Create;
+  fVarFileInfo:=TVersionVarFileInfo.Create;
+
+  for i:=1 to 2 do
+  begin
+    if toread<=0 then exit;
+    tmp:=ReadBlockHeader(block);
+    dec(toread,tmp);
+    if block.key='StringFileInfo' then tmp:=ReadStringFileInfo(block.length-tmp)
+    else if block.key='VarFileInfo' then tmp:=ReadVarFileInfo(block.length-tmp);
+    dec(toread,tmp);
+  end;
+
+end;
+
+procedure TVersionResource.LoadFixedInfos;
+var infodata : TVSFixedFileInfo;
+begin
+  RawData.ReadBuffer(infodata,sizeof(infodata));
+  infodata.FileVersion:=SwapVersion(infodata.FileVersion);
+  infodata.ProductVersion:=SwapVersion(infodata.ProductVersion);
+  infodata.FileDate:=Swap(infodata.FileDate);             //MSLW is stored first...
+  {$IFDEF ENDIAN_BIG}
+  infodata.signature:=SwapEndian(infodata.signature);
+  infodata.verMinor:=SwapEndian(infodata.verMinor);
+  infodata.verMajor:=SwapEndian(infodata.verMajor);
+  infodata.FileFlagsMask:=SwapEndian(infodata.FileFlagsMask);
+  infodata.FileFlags:=SwapEndian(infodata.FileFlags);
+  infodata.FileOS:=SwapEndian(infodata.FileOS);
+  infodata.FileType:=SwapEndian(infodata.FileType);
+  infodata.FileSubType:=SwapEndian(infodata.FileSubType);
+  infodata.FileDate:=SwapEndian(infodata.FileDate);
+  {$ENDIF}
+  fFixedInfo:=TVersionFixedInfo.Create;
+  fFixedInfo.FileVersion:=TFileProductVersion(infodata.FileVersion);
+  fFixedInfo.ProductVersion:=TFileProductVersion(infodata.ProductVersion);
+  fFixedInfo.FileFlagsMask:=infodata.FileFlagsMask;
+  fFixedInfo.FileFlags:=infodata.FileFlags;
+  fFixedInfo.FileOS:=infodata.FileOS;
+  fFixedInfo.FileType:=infodata.FileType;
+  fFixedInfo.FileSubType:=infodata.FileSubType;
+  fFixedInfo.FileDate:=infodata.FileDate;
+end;
+
+function TVersionResource.ReadBlockHeader(out aBlock: TVerBlockHeader
+  ): integer;
+var before : int64;
+begin
+  before:=RawData.Position;
+  RawData.ReadBuffer(aBlock,6);
+  {$IFDEF ENDIAN_BIG}
+  aBlock.length:=SwapEndian(aBlock.length);
+  aBlock.vallength:=SwapEndian(aBlock.vallength);
+  aBlock.valtype:=SwapEndian(aBlock.valtype);
+  {$ENDIF}
+  aBlock.key:=ReadWideString;
+  AlignDWordReading;
+  Result:=RawData.Position-before;
+end;
+
+function TVersionResource.ReadStringFileInfo(toread : integer) : integer;
+var block : TVerBlockHeader;
+    tmp : integer;
+begin
+  Result:=0;
+  while toread>0 do
+  begin
+    tmp:=ReadBlockHeader(block);
+    dec(toread,tmp); inc(Result,tmp);
+    tmp:=ReadStringTable(block.length-tmp,block.key);
+    dec(toread,tmp); inc(Result,tmp);
+  end;
+end;
+
+function TVersionResource.ReadVarFileInfo(toread : integer) : integer;
+var block : TVerBlockHeader;
+    tmp : integer;
+    vinfo : TVerTranslationInfo;
+    before : int64;
+begin
+  Result:=0;
+  while toread>0 do
+  begin
+    before:=RawData.Position;
+    ReadBlockHeader(block);
+    if (block.valtype<>0) or (block.key<>'Translation') then
+      RawData.Seek(block.vallength,soFromCurrent)
+    else
+    begin
+      RawData.ReadBuffer(vinfo,sizeof(vinfo));
+      {$IFDEF ENDIAN_BIG}
+      vinfo.language:=SwapEndian(vinfo.language);
+      vinfo.codepage:=SwapEndian(vinfo.codepage);
+      {$ENDIF}
+      fVarFileInfo.Add(vinfo);
+    end;
+    AlignDWordReading;
+    tmp:=RawData.Position-before;
+    dec(toread,tmp); inc(Result,tmp);
+  end;
+end;
+
+function TVersionResource.ReadStringTable(toread: integer; aName: string
+  ): integer;
+var strtable : TVersionStringTable;
+    tmp : integer;
+    block : TVerBlockHeader;
+    value : string;
+    before : int64;
+begin
+  Result:=0;
+  strtable:=TVersionStringTable.Create(aName);
+  fStringFileInfo.Add(strtable);
+  while toread>0 do
+  begin
+    before:=RawData.Position;
+    ReadBlockHeader(block);
+    value:=ReadWideString;
+    AlignDWordReading;
+    tmp:=RawData.Position-before;
+    dec(toread,tmp); inc(Result,tmp);
+    strtable.Add(block.key,value);
+  end;
+end;
+
+function TVersionResource.ReadWideString: string;
+var w : word;
+    ws : widestring;
+begin
+  ws:='';
+  w:=0;
+  repeat
+    RawData.ReadBuffer(w,2);
+    {$IFDEF ENDIAN_BIG}
+    w:=SwapEndian(w);
+    {$ENDIF}
+    ws:=ws+widechar(w);
+  until w=0;
+  Result:=ws;
+end;
+
+procedure TVersionResource.WriteFixedBlockLength(const position: int64);
+var after : int64;
+    len : word;
+begin
+  after:=RawData.Position;
+  len:=after-position;
+  {$IFDEF ENDIAN_BIG}
+  len:=SwapEndian(len);
+  {$ENDIF}
+  RawData.Position:=position;
+  RawData.WriteBuffer(len,2);
+  RawData.Position:=after;
+end;
+
+procedure TVersionResource.WriteData;
+var block : TVerBlockHeader;
+begin
+  RawData.Size:=0;
+  RawData.Position:=0;
+
+  block.length:=0;
+  block.vallength:=$34;
+  block.valtype:=0;
+  block.key:='VS_VERSION_INFO';
+  {$IFDEF ENDIAN_BIG}
+  block.vallength:=SwapEndian(block.vallength);
+  block.valtype:=SwapEndian(block.valtype);
+  {$ENDIF}
+
+  RawData.WriteBuffer(block,6);
+  WriteWideString(block.key);
+  AlignDWordWriting;
+
+  WriteFixedInfos;
+  AlignDWordWriting;
+
+  if fStringFileInfo.Count>0 then WriteStringFileInfo;
+  if fVarFileInfo.Count>0 then WriteVarFileInfo;
+
+  WriteFixedBlockLength(0);
+end;
+
+procedure TVersionResource.WriteFixedInfos;
+var infodata : TVSFixedFileInfo;
+begin
+  infodata.signature:=$FEEF04BD;
+  infodata.verMinor:=0;
+  infodata.verMajor:=1;
+  infodata.FileVersion:=qword(fFixedInfo.FileVersion);
+  infodata.ProductVersion:=qword(fFixedInfo.ProductVersion);
+  infodata.FileFlagsMask:=fFixedInfo.FileFlagsMask;
+  infodata.FileFlags:=fFixedInfo.FileFlags;
+  infodata.FileOS:=fFixedInfo.FileOS;
+  infodata.FileType:=fFixedInfo.FileType;
+  infodata.FileSubType:=fFixedInfo.FileSubType;
+  infodata.FileDate:=fFixedInfo.FileDate;
+  {$IFDEF ENDIAN_BIG}
+  infodata.signature:=SwapEndian(infodata.signature);
+  infodata.verMinor:=SwapEndian(infodata.verMinor);
+  infodata.verMajor:=SwapEndian(infodata.verMajor);
+  infodata.FileFlagsMask:=SwapEndian(infodata.FileFlagsMask);
+  infodata.FileFlags:=SwapEndian(infodata.FileFlags);
+  infodata.FileOS:=SwapEndian(infodata.FileOS);
+  infodata.FileType:=SwapEndian(infodata.FileType);
+  infodata.FileSubType:=SwapEndian(infodata.FileSubType);
+  infodata.FileDate:=SwapEndian(infodata.FileDate);
+  {$ENDIF}
+  infodata.FileVersion:=SwapVersion(infodata.FileVersion);
+  infodata.ProductVersion:=SwapVersion(infodata.ProductVersion);
+  infodata.FileDate:=Swap(infodata.FileDate);             //MSLW is stored first...
+  RawData.WriteBuffer(infodata,sizeof(infodata));
+end;
+
+procedure TVersionResource.WriteStringFileInfo;
+var block : TVerBlockHeader;
+    i : integer;
+    before : int64;
+begin
+  before:=RawData.Position;
+  block.length:=0;
+  block.vallength:=0;
+  block.valtype:=1;
+  block.key:='StringFileInfo';
+  {$IFDEF ENDIAN_BIG}
+  block.vallength:=SwapEndian(block.vallength);
+  block.valtype:=SwapEndian(block.valtype);
+  {$ENDIF}
+  RawData.WriteBuffer(block,6);
+  WriteWideString(block.key);
+  AlignDWordWriting;
+  
+  for i:=0 to fStringFileInfo.Count-1 do
+    WriteStringTable(fStringFileInfo[i]);
+  
+  WriteFixedBlockLength(before);
+end;
+
+procedure TVersionResource.WriteStringTable(aTable: TVersionStringTable);
+var block : TVerBlockHeader;
+    i : integer;
+    before : int64;
+begin
+  before:=RawData.Position;
+  block.length:=0;
+  block.vallength:=0;
+  block.valtype:=1;
+  block.key:=aTable.Name;
+  {$IFDEF ENDIAN_BIG}
+  block.vallength:=SwapEndian(block.vallength);
+  block.valtype:=SwapEndian(block.valtype);
+  {$ENDIF}
+  RawData.WriteBuffer(block,6);
+  WriteWideString(block.key);
+  AlignDWordWriting;
+
+  for i:=0 to aTable.Count-1 do
+    WriteStringEntry(aTable.Keys[i],aTable.ValuesByIndex[i]);
+
+  WriteFixedBlockLength(before);
+end;
+
+procedure TVersionResource.WriteStringEntry(const aKey, aValue: string);
+var block : TVerBlockHeader;
+    before: int64;
+begin
+  before:=RawData.Position;
+  block.length:=0;
+  block.vallength:=length(aValue)+1;
+  block.valtype:=1;
+  block.key:=aKey;
+  {$IFDEF ENDIAN_BIG}
+  block.vallength:=SwapEndian(block.vallength);
+  block.valtype:=SwapEndian(block.valtype);
+  {$ENDIF}
+  RawData.WriteBuffer(block,6);
+  WriteWideString(block.key);
+  AlignDWordWriting;
+  WriteWideString(aValue);
+  AlignDWordWriting;
+
+  WriteFixedBlockLength(before);
+end;
+
+procedure TVersionResource.WriteVarFileInfo;
+var block : TVerBlockHeader;
+    i : integer;
+    before : int64;
+begin
+  before:=RawData.Position;
+  block.length:=0;
+  block.vallength:=0;
+  block.valtype:=1;
+  block.key:='VarFileInfo';
+  {$IFDEF ENDIAN_BIG}
+  block.vallength:=SwapEndian(block.vallength);
+  block.valtype:=SwapEndian(block.valtype);
+  {$ENDIF}
+  RawData.WriteBuffer(block,6);
+  WriteWideString(block.key);
+  AlignDWordWriting;
+
+  for i:=0 to fVarFileInfo.Count-1 do
+    WriteVarEntry(fVarFileInfo[i]);
+
+  WriteFixedBlockLength(before);
+end;
+
+procedure TVersionResource.WriteVarEntry(aEntry: TVerTranslationInfo);
+var block : TVerBlockHeader;
+    before: int64;
+begin
+  before:=RawData.Position;
+  block.length:=0;
+  block.vallength:=4;
+  block.valtype:=0;
+  block.key:='Translation';
+  {$IFDEF ENDIAN_BIG}
+  block.vallength:=SwapEndian(block.vallength);
+  block.valtype:=SwapEndian(block.valtype);
+  aEntry.language:=SwapEndian(aEntry.language);
+  aEntry.codepage:=SwapEndian(aEntry.codepage);
+  {$ENDIF}
+  RawData.WriteBuffer(block,6);
+  WriteWideString(block.key);
+  AlignDWordWriting;
+  RawData.WriteBuffer(aEntry,sizeof(aEntry));
+  WriteFixedBlockLength(before);
+end;
+
+procedure TVersionResource.WriteWideString(const aString: string);
+var ws : widestring;
+    w : word;
+    i : integer;
+begin
+  ws:=aString;
+  for i:=1 to length(ws) do
+  begin
+    w:=word(ws[i]);
+    {$IFDEF ENDIAN_BIG}
+    w:=SwapEndian(w);
+    {$ENDIF}
+    RawData.WriteBuffer(w,2);
+  end;
+  w:=0;
+  RawData.WriteBuffer(w,2);
+end;
+
+function TVersionResource.GetType: TResourceDesc;
+begin
+  Result:=fType;
+end;
+
+function TVersionResource.GetName: TResourceDesc;
+begin
+  Result:=fName;
+end;
+
+function TVersionResource.ChangeDescTypeAllowed(aDesc: TResourceDesc): boolean;
+begin
+  Result:=false;
+end;
+
+function TVersionResource.ChangeDescValueAllowed(aDesc: TResourceDesc
+  ): boolean;
+begin
+  Result:=false;
+end;
+
+procedure TVersionResource.NotifyResourcesLoaded;
+begin
+end;
+
+constructor TVersionResource.Create;
+begin
+  inherited Create;
+  fType:=TResourceDesc.Create(RT_VERSION);
+  fName:=TResourceDesc.Create(1);
+  SetDescOwner(fType);
+  SetDescOwner(fName);
+  fFixedInfo:=nil;
+  fStringFileInfo:=nil;
+  fVarFileInfo:=nil;
+end;
+
+constructor TVersionResource.Create(aType, aName: TResourceDesc);
+begin
+  Create;
+end;
+
+destructor TVersionResource.Destroy;
+begin
+  fType.Free;
+  fName.Free;
+  if fFixedInfo<>nil then fFixedInfo.Free;
+  if fStringFileInfo<>nil then fStringFileInfo.Free;
+  if fVarFileInfo<>nil then fVarFileInfo.Free;
+  inherited Destroy;
+end;
+
+procedure TVersionResource.UpdateRawData;
+begin
+  if fFixedInfo=nil then exit;
+  WriteData;
+  FreeAndNil(fFixedInfo);
+  FreeAndNil(fStringFileInfo);
+  FreeAndNil(fVarFileInfo);
+end;
+
+initialization
+  TResourceFactory.RegisterResourceClass(RT_VERSION,TVersionResource);
+
+end.

+ 377 - 0
packages/fcl-res/src/versiontypes.pp

@@ -0,0 +1,377 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Classes used by version information resource
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit versiontypes;
+
+{$MODE OBJFPC}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+  
+type
+  EVersionStringTableException = class(Exception);
+  ENameNotAllowedException = class(EVersionStringTableException);
+  EKeyNotFoundException = class(EVersionStringTableException);
+  EDuplicateKeyException = class(EVersionStringTableException);
+
+resourcestring
+  SVerStrTableNameNotAllowed = 'Name ''%s'' is not a valid 8-cipher hex sequence';
+  SVerStrTableKeyNotFound    = 'Key ''%s'' not found';
+  SVerStrTableDuplicateKey   = 'Duplicate key ''%s''';
+
+type
+  TFileProductVersion = array[0..3] of word;
+  
+  TVerTranslationInfo = packed record
+    language : word;
+    codepage : word;
+  end;
+  PVerTranslationInfo = ^TVerTranslationInfo;
+
+type
+
+  { TVersionFixedInfo }
+
+  TVersionFixedInfo = class
+  private
+    fFileVersion : TFileProductVersion;
+    fProductVersion : TFileProductVersion;
+    fFileFlagsMask : longword;
+    fFileFlags : longword;
+    fFileOS : longword;
+    fFileType : longword;
+    fFileSubType : longword;
+    fFileDate : qword;
+  protected
+  public
+    constructor Create;
+    property FileVersion : TFileProductVersion read fFileVersion write fFileVersion;
+    property ProductVersion : TFileProductVersion read fProductVersion write fProductVersion;
+    property FileFlagsMask : longword read fFileFlagsMask write fFileFlagsMask;
+    property FileFlags : longword read fFileFlags write fFileFlags;
+    property FileOS : longword read fFileOS write fFileOS;
+    property FileType : longword read fFileType write fFileType;
+    property FileSubType : longword read fFileSubType write fFileSubType;
+    property FileDate : qword read fFileDate write fFileDate;
+  end;
+
+  { TVersionStringTable }
+
+  TVersionStringTable = class
+  private
+    fName : string;
+    fKeys : TStringList;
+    fValues : TStringList;
+    function GetCount : integer;
+    function GetKey(index : integer) : string;
+    function GetValue(index : integer) : string; overload;
+    function GetValue(aKey : string) : string; overload;
+    function CheckName(const aName : string) : boolean;
+    function KeyToIndex(const aKey : string) : integer;
+    procedure SetValue(index : integer; aValue : string); overload;
+    procedure SetValue(aKey : string; aValue : string); overload;
+  protected
+  public
+    constructor Create(const aName : string);
+    destructor Destroy; override;
+    procedure Add(const aKey,aValue : string);
+    procedure Clear;
+    procedure Delete(const aIndex : integer); overload;
+    procedure Delete(const aKey : string); overload;
+    property Name : string read fName;
+    property Count : integer read GetCount;
+    property Keys[index : integer] : string read GetKey;
+    property ValuesByIndex[index : integer] : string read GetValue write SetValue;
+    property Values[Key : string] : string read GetValue write SetValue; default;
+  end;
+
+
+  { TVersionStringFileInfo }
+
+  TVersionStringFileInfo = class
+  private
+    fList : TFPList;
+  protected
+    function GetCount : integer;
+    function GetItem(index : integer) : TVersionStringTable;
+    procedure SetItem(index : integer; aValue : TVersionStringTable);
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Add(aStrTable : TVersionStringTable);
+    procedure Clear;
+    procedure Delete(const aIndex : integer);
+    property Count : integer read GetCount;
+    property Items[index : integer] : TVersionStringTable read GetItem write SetItem; default;
+  end;
+  
+  { TVersionVarFileInfo }
+
+  TVersionVarFileInfo = class
+  private
+    fList : TFPList;
+  protected
+    function GetCount : integer;
+    function GetItem(index : integer) : TVerTranslationInfo;
+    procedure SetItem(index : integer; aValue : TVerTranslationInfo);
+  public
+    constructor Create;
+    destructor Destroy; override;
+    procedure Add(aInfo : TVerTranslationInfo);
+    procedure Clear;
+    procedure Delete(const aIndex : integer);
+    property Count : integer read GetCount;
+    property Items[index : integer] : TVerTranslationInfo read GetItem write SetItem; default;
+  end;
+
+
+implementation
+
+uses
+  versionconsts;
+
+{ TVersionStringTable }
+
+function TVersionStringTable.GetCount: integer;
+begin
+  Result:=fKeys.Count;
+end;
+
+function TVersionStringTable.GetKey(index: integer): string;
+begin
+  Result:=fKeys[index];
+end;
+
+function TVersionStringTable.GetValue(index: integer): string;
+begin
+  Result:=fValues[index];
+end;
+
+function TVersionStringTable.GetValue(aKey: string): string;
+var idx : integer;
+begin
+  idx:=KeyToIndex(aKey);
+  if idx=-1 then
+    raise EKeyNotFoundException.CreateFmt(SVerStrTableKeyNotFound,[aKey]);
+  Result:=fValues[idx];
+end;
+
+procedure TVersionStringTable.SetValue(index: integer; aValue: string);
+begin
+  fValues[index]:=aValue;
+end;
+
+procedure TVersionStringTable.SetValue(aKey: string; aValue: string);
+var idx : integer;
+begin
+  idx:=KeyToIndex(aKey);
+  if idx=-1 then
+    raise EKeyNotFoundException.CreateFmt(SVerStrTableKeyNotFound,[aKey]);
+  fValues[idx]:=aValue;
+end;
+
+function TVersionStringTable.CheckName(const aName: string): boolean;
+var i : integer;
+begin
+  Result:=false;
+  if length(aName)<>8 then exit;
+  for i:=1 to 8 do
+    if not (aName[i] in ['0'..'9','A'..'F','a'..'f']) then exit;
+  Result:=true;
+end;
+
+function TVersionStringTable.KeyToIndex(const aKey: string): integer;
+var i : integer;
+begin
+  for i:=0 to fKeys.Count-1 do
+    if fKeys[i]=aKey then
+    begin
+      Result:=i;
+      exit;
+    end;
+  Result:=-1;
+end;
+
+constructor TVersionStringTable.Create(const aName: string);
+begin
+  fKeys:=TStringList.Create;
+  fValues:=TStringList.Create;
+  if not CheckName(aName) then
+    raise ENameNotAllowedException.CreateFmt(SVerStrTableNameNotAllowed,[aName]);
+  fName:=aName;
+end;
+
+destructor TVersionStringTable.Destroy;
+begin
+  fKeys.Free;
+  fValues.Free;
+end;
+
+procedure TVersionStringTable.Add(const aKey, aValue: string);
+begin
+  if KeyToIndex(aKey)<>-1 then
+    raise EDuplicateKeyException.CreateFmt(SVerStrTableDuplicateKey,[aKey]);
+  fKeys.Add(aKey);
+  fValues.Add(aValue);
+end;
+
+procedure TVersionStringTable.Clear;
+begin
+  fKeys.Clear;
+  fValues.Clear;
+end;
+
+procedure TVersionStringTable.Delete(const aIndex: integer);
+begin
+  fKeys.Delete(aIndex);
+  fValues.Delete(aIndex);
+end;
+
+procedure TVersionStringTable.Delete(const aKey: string);
+var idx : integer;
+begin
+  idx:=KeyToIndex(aKey);
+  if idx=-1 then
+    raise EKeyNotFoundException.CreateFmt(SVerStrTableKeyNotFound,[aKey]);
+  Delete(idx);
+end;
+
+{ TVersionStringFileInfo }
+
+function TVersionStringFileInfo.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+function TVersionStringFileInfo.GetItem(index: integer): TVersionStringTable;
+begin
+  Result:=TVersionStringTable(fList[index]);
+end;
+
+procedure TVersionStringFileInfo.SetItem(index: integer;
+  aValue: TVersionStringTable);
+begin
+  fList[index]:=aValue;
+end;
+
+constructor TVersionStringFileInfo.Create;
+begin
+  fList:=TFPList.Create;
+end;
+
+destructor TVersionStringFileInfo.Destroy;
+begin
+  Clear;
+  fList.Free;
+end;
+
+procedure TVersionStringFileInfo.Add(aStrTable: TVersionStringTable);
+begin
+  fList.Add(aStrTable);
+end;
+
+procedure TVersionStringFileInfo.Clear;
+var i : integer;
+begin
+  for i:=0 to fList.Count-1 do
+    TVersionStringTable(fList[i]).Free;
+  fList.Clear;
+end;
+
+procedure TVersionStringFileInfo.Delete(const aIndex: integer);
+begin
+  TVersionStringTable(fList[aIndex]).Free;
+  fList.Delete(aIndex);
+end;
+
+{ TVersionFixedInfo }
+
+constructor TVersionFixedInfo.Create;
+begin
+  FillByte(fFileVersion,Sizeof(TFileProductVersion),0);
+  FillByte(fProductVersion,Sizeof(TFileProductVersion),0);
+  fFileFlagsMask:=VS_FFI_FILEFLAGSMASK;
+  fFileFlags:=0;
+  fFileOS:=VOS_NT_WINDOWS32;
+  fFileType:=VFT_APP;
+  fFileSubType:=VFT2_UNKNOWN;
+  fFileDate:=0;
+end;
+
+{ TVersionVarFileInfo }
+
+function TVersionVarFileInfo.GetCount: integer;
+begin
+  Result:=fList.Count;
+end;
+
+function TVersionVarFileInfo.GetItem(index: integer): TVerTranslationInfo;
+begin
+  Result:=PVerTranslationInfo(fList[index])^;
+end;
+
+procedure TVersionVarFileInfo.SetItem(index: integer;
+  aValue: TVerTranslationInfo);
+var p1,p2 : PVerTranslationInfo;
+begin
+  p1:=PVerTranslationInfo(fList[index]);
+  FreeMem(p1);
+  GetMem(p2,sizeof(TVerTranslationInfo));
+  p2^:=aValue;
+  fList[index]:=p2;
+end;
+
+constructor TVersionVarFileInfo.Create;
+begin
+  fList:=TFPList.Create;
+end;
+
+destructor TVersionVarFileInfo.Destroy;
+begin
+  Clear;
+  fList.Free;
+end;
+
+procedure TVersionVarFileInfo.Add(aInfo: TVerTranslationInfo);
+var p : PVerTranslationInfo;
+begin
+  GetMem(p,sizeof(TVerTranslationInfo));
+  p^:=aInfo;
+  fList.Add(p);
+end;
+
+procedure TVersionVarFileInfo.Clear;
+var p : PVerTranslationInfo;
+    i : integer;
+begin
+  for i:=0 to fList.Count-1 do
+  begin
+    p:=PVerTranslationInfo(fList[i]);
+    FreeMem(p);
+  end;
+  fList.Clear;
+end;
+
+procedure TVersionVarFileInfo.Delete(const aIndex: integer);
+var p : PVerTranslationInfo;
+begin
+  p:=PVerTranslationInfo(fList[aIndex]);
+  FreeMem(p);
+  fList.Delete(aIndex);
+end;
+
+end.

+ 126 - 0
packages/fcl-res/src/winpeimagereader.pp

@@ -0,0 +1,126 @@
+{
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2008 by Giulio Bernardi
+
+    Resource reader for PE image files
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+unit winpeimagereader;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource, coffreader;
+
+type
+
+  { TWinPEImageResourceReader }
+
+  TWinPEImageResourceReader = class (TAbstractResourceReader)
+  private
+    fDescription: string;
+    fExtensions: string;
+    fCoffReader : TCoffResourceReader;
+  protected
+    function CheckDosStub(aStream : TStream) : boolean;
+    function CheckPESignature(aStream : TStream) : boolean;
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Load(aResources : TResources; aStream : TStream); override;
+    function CheckMagic(aStream : TStream) : boolean; override;
+  public
+    constructor Create; override;
+    destructor Destroy; override;
+  end;
+
+implementation
+
+const
+  PESignatureOffset = $3C;
+
+{ TWinPEImageResourceReader }
+
+function TWinPEImageResourceReader.CheckDosStub(aStream: TStream): boolean;
+var w : word;
+    lw : longword;
+begin
+  Result:=false;
+  try
+    aStream.ReadBuffer(w,2);
+  except
+    on e : EReadError do exit;
+  end;
+
+  {$IFDEF ENDIAN_BIG}
+  w:=SwapEndian(w);
+  {$ENDIF}
+  Result:=w=$5A4D; //MZ
+  if not Result then exit;
+  aStream.Position:=PESignatureOffset;
+  aStream.ReadBuffer(lw,4);
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  aStream.Position:=lw;
+end;
+
+function TWinPEImageResourceReader.CheckPESignature(aStream: TStream): boolean;
+var lw : longword;
+begin
+  aStream.ReadBuffer(lw,4);
+  {$IFDEF ENDIAN_BIG}
+  lw:=SwapEndian(lw);
+  {$ENDIF}
+  Result:=lw=$00004550; //PE#0#0
+end;
+
+function TWinPEImageResourceReader.GetExtensions: string;
+begin
+  Result:=fExtensions;
+end;
+
+function TWinPEImageResourceReader.GetDescription: string;
+begin
+  Result:=fDescription;
+end;
+
+procedure TWinPEImageResourceReader.Load(aResources: TResources; aStream: TStream);
+begin
+  if not CheckMagic(aStream) then
+    raise EResourceReaderWrongFormatException.Create('');
+  CallSubReaderLoad(fCoffReader,aResources,aStream);
+end;
+
+function TWinPEImageResourceReader.CheckMagic(aStream: TStream): boolean;
+begin
+  Result:=CheckDosStub(aStream) and CheckPESignature(aStream);
+end;
+
+constructor TWinPEImageResourceReader.Create;
+begin
+  fExtensions:='.exe .dll .bpl';
+  fDescription:='Win32 PE image resource reader';
+  fCoffReader:=TCoffResourceReader.Create;
+end;
+
+destructor TWinPEImageResourceReader.Destroy;
+begin
+  fCoffReader.Free;
+end;
+
+initialization
+  TResources.RegisterReader('.exe',TWinPEImageResourceReader);
+  TResources.RegisterReader('.dll',TWinPEImageResourceReader);
+  TResources.RegisterReader('.bpl',TWinPEImageResourceReader);
+
+end.

+ 228 - 0
packages/fcl-res/xml/acceleratorsresource.xml

@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    acceleratorsresource
+  ====================================================================
+-->
+
+<module name="acceleratorsresource">
+<short>Contains an accelerator table resource type</short>
+<descr>
+<p>This unit contains <link id="TAcceleratorsResource"/>, a <link id="resource.TAbstractResource">TAbstractResource</link> descendant specialized in handling resource of type <link id="resource.RT_ACCELERATOR">RT_ACCELERATOR</link>.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TAcceleratorsResource"/> for type <link id="resource.RT_ACCELERATOR">RT_ACCELERATOR</link> with <link id="resfactory.TResourceFactory">TResourceFactory</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- constant Visibility: default -->
+<element name="FVirtKey">
+<short>The accelerator key is a virtual key code</short>
+<descr>
+<p>When this flag is set, the accelerator key is a virtual key code. Otherwise, it is a ASCII character</p>
+</descr>
+<seealso>
+<link id="TAccelerator"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="FNoInvert">
+<short>Obsolete</short>
+<descr>
+<p>This flag is obsolete and is provided only for compatibility with 16 bit Windows.</p>
+</descr>
+<seealso>
+<link id="TAccelerator"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="FShift">
+<short>The accelerator is activated only if <var>SHIFT</var> key is pressed</short>
+<descr>
+<p>This flag is valid only if the key is a virtual key.</p>
+</descr>
+<seealso>
+<link id="TAccelerator"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="FControl">
+<short>The accelerator is activated only if <var>CTRL</var> key is pressed</short>
+<descr>
+<p>This flag is valid only if the key is a virtual key.</p>
+</descr>
+<seealso>
+<link id="TAccelerator"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="FAlt">
+<short>The accelerator is activated only if <var>ALT</var> key is pressed</short>
+<descr>
+<p>This flag is valid only if the key is a virtual key.</p>
+</descr>
+<seealso>
+<link id="TAccelerator"/>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TAccelerator">
+<short>A single accelerator entry</short>
+<descr>
+<p>A single accelerator entry in the accelerator table resource.</p>
+<p>The key associated with the accelerator is represented by <var>Ansi</var> field: it can be a character or a virtual-key code (in the latter case, <link id="FVirtKey"/> flag must be active).</p>
+<p>The accelerator is identified by the value of <var>id</var> field.</p>
+<p><var>Flags</var> is a combination of the following values:</p>
+<ul>
+<li><link id="FVirtKey"/></li>
+<li><link id="FShift"/></li>
+<li><link id="FNoInvert"/></li>
+<li><link id="FControl"/></li>
+<li><link id="FAlt"/></li>
+</ul>
+</descr>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TAccelerator.Flags">
+<short>A set of flags that can be combined to specify an accelerator's characteristics.</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TAccelerator.Ansi">
+<short>An ANSI character value or a virtual-key code</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TAccelerator.Id">
+<short>An integer value that identifies the accelerator</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TAccelerator.padding">
+<short>Used to keep record size aligned on a DWORD boundary</short>
+</element>
+
+<!-- pointer type Visibility: default -->
+<element name="PAccelerator">
+<short>A pointer to a TAccelerator record</short>
+<seealso>
+<link id="TAccelerator"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TAcceleratorsResource">
+<short>Accelerator table resource type</short>
+<descr>
+<p>This class represents a resource of type <link id="resource.RT_ACCELERATOR">RT_ACCELERATOR</link>.</p>
+<p>An accelerator table resource is a collection of accelerators (represented by <link id="TAccelerator"/> records).</p>
+<p>An accelerator represents a keystroke that can be associated with some action.</p>
+<p>This resource type is very Microsoft Windows-specific, so it might not be of interest for many users.</p>
+<p>Methods are provided to add, delete and modify single accelerators.</p>
+<remark>This class doesn't allow its type to be changed to anything else than <link id="resource.RT_ACCELERATOR">RT_ACCELERATOR</link>. Attempts to do so result in a <link id="resource.EResourceDescChangeNotAllowedException">EResourceDescChangeNotAllowedException</link>.</remark>
+</descr>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TAcceleratorsResource.Create">
+<short>Creates a new accelerator table resource</short>
+<descr>
+<p>Please note that <var>aType</var> parameter is not used, since this class always uses <link id="resource.RT_ACCELERATOR">RT_ACCELERATOR</link> as type.</p>
+</descr>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAcceleratorsResource.Create.aType">
+<short>Ignored. Can be <var>nil</var>.</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAcceleratorsResource.Create.aName">
+<short>The name of the resource</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TAcceleratorsResource.Add">
+<short>Adds a new accelerator to the table</short>
+<seealso>
+<link id="TAcceleratorsResource.Items"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAcceleratorsResource.Add.aItem">
+<short>The accelerator to add</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TAcceleratorsResource.Clear">
+<short>Empties the accelerator table</short>
+<seealso>
+<link id="TAcceleratorsResource.Items"/>
+<link id="TAcceleratorsResource.Delete"/>
+</seealso>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TAcceleratorsResource.Delete">
+<short>Deletes an accelerator from the table</short>
+<seealso>
+<link id="TAcceleratorsResource.Items"/>
+<link id="TAcceleratorsResource.Clear"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAcceleratorsResource.Delete.aIndex">
+<short>The index of the accelerator to delete</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAcceleratorsResource.Count">
+<short>The number of accelerators in the table</short>
+<seealso>
+<link id="TAcceleratorsResource.Items"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAcceleratorsResource.Items">
+<short>Indexed array of accelerators in the table</short>
+<descr>
+<p>This property can be used to access all accelerators in the object.</p>
+<remark>This array is 0-based: valid elements range from 0 to <link id="TAcceleratorsResource.Count">Count</link>-1.</remark>
+<remark>If you need to access <link id="resource.TAbstractResource.RawData">RawData</link> after you added, deleted or modified accelerators, be sure to call <link id="resource.TAbstractResource.UpdateRawData">UpdateRawData</link> first. This isn't needed however when resource is written to a stream, since <link id="resource.TResources">TResources</link> takes care of it.</remark>
+</descr>
+<seealso>
+<link id="TAcceleratorsResource.Count"/>
+<link id="TAccelerator"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAcceleratorsResource.Items.index">
+<short>The index of the accelerator to access</short>
+</element>
+
+</module> <!-- acceleratorsresource -->
+
+</package>
+</fpdoc-descriptions>

+ 120 - 0
packages/fcl-res/xml/bitmapresource.xml

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    bitmapresource
+  ====================================================================
+-->
+
+<module name="bitmapresource">
+<short>Contains a bitmap resource type</short>
+<descr>
+<p>This unit contains <link id="TBitmapResource"/>, a <link id="resource.TAbstractResource">TAbstractResource</link> descendant specialized in handling resource of type <link id="resource.RT_BITMAP">RT_BITMAP</link>.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TBitmapResource"/> for type <link id="resource.RT_BITMAP">RT_BITMAP</link> with <link id="resfactory.TResourceFactory">TResourceFactory</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TBitmapResource">
+<short>Bitmap resource type</short>
+<descr>
+<p>This class represents a resource of type <link id="resource.RT_BITMAP">RT_BITMAP</link>.</p>
+<p>A bitmap resource contents is very similar to a BMP file. However some differences exists, so <link id="resource.TAbstractResource.RawData">RawData</link> is not appropriate if you need to read and write BMP data. Instead, <link id="TBitmapResource.BitmapData">BitmapData</link> property gives access to a BMP file-like stream.</p>
+<remark>This class doesn't allow its type to be changed to anything else than <link id="resource.RT_BITMAP">RT_BITMAP</link>. Attempts to do so result in a <link id="resource.EResourceDescChangeNotAllowedException">EResourceDescChangeNotAllowedException</link>.</remark>
+</descr>
+<seealso>
+<link id="TBitmapResource.BitmapData">BitmapData</link>
+<link id="resource.TAbstractResource.RawData">TAbstractResource.RawData</link>
+</seealso>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TBitmapResource.Create">
+<short>Creates a new bitmap resource</short>
+<descr>
+<p>Please note that <var>aType</var> parameter is not used, since this class always uses <link id="resource.RT_BITMAP">RT_BITMAP</link> as type.</p>
+</descr>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TBitmapResource.Create.aType">
+<short>Ignored. Can be <var>nil</var>.</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TBitmapResource.Create.aName">
+<short>The name of the resource</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TBitmapResource.SetCustomBitmapDataStream">
+<short>Sets a custom stream as the underlying stream for BitmapData</short>
+<descr>
+<p>This method allows the user to use a custom stream as the underlying stream for <link id="TBitmapResource.BitmapData">BitmapData</link>. This is useful when you want a <link id="TBitmapResource"/> to be created from a bmp file for which you have a stream.</p>
+<p><b>Sample code</b></p>
+<p>This code creates a resource containing a bitmap</p>
+<code>
+var
+  aName : TResourceDesc;
+  aRes : TBitmapResource;
+  aFile : TFileStream;
+  Resources : TResources;
+begin
+  Resources:=TResources.Create;
+  aName:=TResourceDesc.Create('MYBITMAP');
+  aRes:=TBitmapResource.Create(nil,aName); //type is always RT_BITMAP
+  aName.Free; //not needed anymore
+  aFile:=TFileStream.Create('mybitmap.bmp',fmOpenRead or fmShareDenyNone);
+  aRes.SetCustomBitmapDataStream(aFile);
+  Resources.Add(aRes);
+  Resources.WriteToFile('myresource.res');
+
+  Resources.Free; //it destroys aRes as well.
+  aFile.Free;
+end;
+</code>
+</descr>
+<seealso>
+<link id="TBitmapResource.BitmapData"/>
+<link id="resource.TAbstractResource.UpdateRawData">TAbstractResource.UpdateRawData</link>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TBitmapResource.SetCustomBitmapDataStream.aStream">
+<short>The custom stream to use as the underlying <link id="TBitmapResource.BitmapData">BitmapData</link> stream</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TBitmapResource.BitmapData">
+<short>Resource data as a BMP stream</short>
+<descr>
+<p><link id="TBitmapResource.BitmapData">BitmapData</link> property gives access to resource data in a  BMP file-like stream, unlike <link id="resource.TAbstractResource.RawData">RawData</link>.</p>
+<p><link id="TBitmapResource.BitmapData">BitmapData</link> does not create a copy of <link id="resource.TAbstractResource.RawData">RawData</link> so memory usage is generally kept limited.</p>
+<p>You can also set a custom stream as the underlying stream for <link id="TBitmapResource.BitmapData">BitmapData</link> via <link id="TBitmapResource.SetCustomBitmapDataStream">SetCustomBitmapDataStream</link>, much like <link id="resource.TAbstractResource.SetCustomRawDataStream">SetCustomRawDataStream</link> does for <link id="resource.TAbstractResource.RawData">RawData</link>. This is useful when you want a <link id="TBitmapResource"/> to be created from a bmp file for which you have a stream.</p>
+<remark>If you need to access <link id="resource.TAbstractResource.RawData">RawData</link> after you modified <link id="TBitmapResource.BitmapData">BitmapData</link>, be sure to call <link id="resource.TAbstractResource.UpdateRawData">UpdateRawData</link> first. This isn't needed however when resource is written to a stream, since <link id="resource.TResources">TResources</link> takes care of it.</remark>
+</descr>
+<seealso>
+<link id="TBitmapResource.SetCustomBitmapDataStream"/>
+<link id="resource.TAbstractResource.RawData">TAbstractResource.RawData</link>
+<link id="resource.TAbstractResource.UpdateRawData">TAbstractResource.UpdateRawData</link>
+</seealso>
+</element>
+
+</module> <!-- bitmapresource -->
+
+</package>
+</fpdoc-descriptions>

+ 32 - 0
packages/fcl-res/xml/clean.sh

@@ -0,0 +1,32 @@
+#!/bin/bash
+rm *.html
+rm -Rf resource
+rm -Rf resourcetree
+rm -Rf resdatastream
+rm -Rf resfactory
+rm -Rf acceleratorsresource
+rm -Rf bitmapresource
+rm -Rf groupresource
+rm -Rf groupiconresource
+rm -Rf groupcursorresource
+rm -Rf stringtableresource
+rm -Rf versionconsts
+rm -Rf versiontypes
+rm -Rf versionresource
+rm -Rf resreader
+rm -Rf reswriter
+rm -Rf cofftypes
+rm -Rf coffreader
+rm -Rf coffwriter
+rm -Rf winpeimagereader
+rm -Rf elfconsts
+rm -Rf elfreader
+rm -Rf elfwriter
+rm -Rf machotypes
+rm -Rf machoreader
+rm -Rf machowriter
+rm -Rf externaltypes
+rm -Rf externalreader
+rm -Rf externalwriter
+rm -Rf dfmreader
+

+ 70 - 0
packages/fcl-res/xml/coffreader.xml

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    coffreader
+  ====================================================================
+-->
+
+<module name="coffreader">
+<short>Contains a resource reader for COFF files</short>
+<descr>
+<p>This unit contains <link id="TCoffResourceReader"/>, a <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link> descendant that is able to read COFF object files containing resources.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TCoffResourceReader"/> with <link id="resource.TResources">TResources</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resourcetree">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="cofftypes">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TCoffResourceReader">
+<short>COFF resource reader</short>
+<descr>
+<p>This class provides a reader for COFF object files containing resources.</p>
+<p>COFF is the file format used by Microsoft Windows object files. Usually resources get stored in a object file that can be given to a linker to produce an executable.</p>
+<p>After an object file has been read, <link id="TCoffResourceReader.MachineType">MachineType</link> property holds the machine type the object file was built for.</p>
+<remark>This reader is not able to read full PE images. Use <link id="winpeimagereader.TWinPEImageResourceReader">TWinPEImageResourceReader</link> instead.</remark>
+</descr>
+<seealso>
+<link id="TCoffResourceReader.MachineType"/>
+<link id="resource.TAbstractResourceReader">TAbstractResourceReader</link>
+<link id="winpeimagereader.TWinPEImageResourceReader">TWinPEImageResourceReader</link>
+<link id="coffwriter.TCoffResourceWriter">TCoffResourceWriter</link>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TCoffResourceReader.MachineType">
+<short>The machine type of the object file</short>
+<descr>
+<p>This property holds the machine type of the object file that has been read.</p>
+<remark>Obviously, this property is meaningful only after an object file has been read.</remark>
+</descr>
+<seealso>
+<link id="cofftypes.TCoffMachineType">TCoffMachineType</link>
+</seealso>
+</element>
+
+</module> <!-- coffreader -->
+
+</package>
+</fpdoc-descriptions>

+ 49 - 0
packages/fcl-res/xml/cofftypes.xml

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    cofftypes
+  ====================================================================
+-->
+
+<module name="cofftypes">
+<short>Contains types used by COFF resource reader and writer</short>
+<descr>
+<p>These types are used internally by <link id="coffwriter.TCoffResourceWriter">TCoffResourceWriter</link> and <link id="coffreader.TCoffResourceReader">TCoffResourceReader</link>.</p>
+<p>The only type of interest for the user is <link id="TCoffMachineType"/>.</p>
+</descr>
+
+<!-- enumeration type Visibility: default -->
+<element name="TCoffMachineType">
+<short>Enumeration for COFF machine type</short>
+<descr>
+<p>This enumeration specifies the COFF machine type.</p>
+<p>It is used by <link id="coffwriter.TCoffResourceWriter">TCoffResourceWriter</link> to specify the machine type of the generated object file and by <link id="coffreader.TCoffResourceReader">TCoffResourceReader</link> to read the machine type of the object file that has been read.</p>
+</descr>
+<seealso>
+<link id="coffwriter.TCoffResourceWriter.MachineType">TCoffResourceWriter.MachineType</link>
+<link id="coffreader.TCoffResourceReader.MachineType">TCoffResourceReader.MachineType</link>
+</seealso>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TCoffMachineType.cmti386">
+<short>Intel i386</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TCoffMachineType.cmtarm">
+<short>ARM</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TCoffMachineType.cmtx8664">
+<short>AMD x86_64</short>
+</element>
+
+</module> <!-- cofftypes -->
+
+</package>
+</fpdoc-descriptions>

+ 99 - 0
packages/fcl-res/xml/coffwriter.xml

@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    coffwriter
+  ====================================================================
+-->
+
+<module name="coffwriter">
+<short>Contains a resource writer for COFF files</short>
+<descr>
+<p>This unit contains <link id="TCoffResourceWriter"/>, a <link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link> descendant that is able to write COFF object files containing resources.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TCoffResourceWriter"/> with <link id="resource.TResources">TResources</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resourcetree">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="cofftypes">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TResourceStringTable">
+<short>COFF resource string table</short>
+<descr>
+<p>This class is used internally by <link id="TCoffResourceWriter"/>.</p>
+</descr>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TCoffRelocation">
+<short>COFF relocation type</short>
+<descr>
+<p>This record is used internally by <link id="TCoffResourceWriter"/>.</p>
+</descr>
+</element>
+
+<!-- pointer type Visibility: default -->
+<element name="PCoffRelocation">
+<short>Pointer to a COFF relocation</short>
+<descr>
+<p>This type is used internally by <link id="TCoffResourceWriter"/>.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TCoffRelocations">
+<short>COFF relocation table</short>
+<descr>
+<p>This class is used internally by <link id="TCoffResourceWriter"/>.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TCoffResourceWriter">
+<short>COFF resource writer</short>
+<descr>
+<p>This class provides a writer for COFF object files containing resources.</p>
+<p>COFF is the file format used by Microsoft Windows object files. Usually resources get stored in a object file that can be given to a linker to produce an executable.</p>
+<p><link id="TCoffResourceWriter.MachineType">MachineType</link> property can be used to set the machine type of the object file to generate.</p>
+</descr>
+<seealso>
+<link id="TCoffResourceWriter.MachineType"/>
+<link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link>
+<link id="coffreader.TCoffResourceReader">TCoffResourceWriter</link>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TCoffResourceWriter.MachineType">
+<short>The machine type of the object file</short>
+<descr>
+<p>This property can be used to set the machine type of the object file to write.</p>
+</descr>
+<seealso>
+<link id="cofftypes.TCoffMachineType">TCoffMachineType</link>
+</seealso>
+</element>
+
+</module> <!-- coffwriter -->
+
+</package>
+</fpdoc-descriptions>

+ 43 - 0
packages/fcl-res/xml/dfmreader.xml

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    dfmreader
+  ====================================================================
+-->
+
+<module name="dfmreader">
+<short>Contains a resource reader for DFM files</short>
+<descr>
+<p>This unit contains <link id="TDfmResourceReader"/>, a <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link> descendant used to compile DFM files to resources.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TDfmResourceReader"/> with <link id="resource.TResources">TResources</link>.</p>
+
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TDfmResourceReader">
+<short>DFM resource reader</short>
+<descr>
+<p>This class isn't a proper resource reader. It provides a quick way to create a resource file from a DFM/XFM/LFM file, similar to what Delphi does with constructs like <var>{$R *.dfm}</var>.</p>
+<p>This class reads a DFM, XFM or LFM file, compiles it to binary format if it isn't, and stores it in a resource of type <link id="resource.RT_RCDATA">RT_RCDATA</link> with the name of the form specified in the DFM file.</p>
+</descr>
+</element>
+
+</module> <!-- dfmreader -->
+
+</package>
+</fpdoc-descriptions>

+ 807 - 0
packages/fcl-res/xml/elfconsts.xml

@@ -0,0 +1,807 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    elfconsts
+  ====================================================================
+-->
+
+<module name="elfconsts">
+<short>Contains constants used by ELF reader and writer</short>
+<descr>
+<p>These constants are used internally by <link id="elfwriter.TElfResourceWriter">TElfResourceWriter</link> and <link id="elfreader.TElfResourceReader">TElfResourceReader</link>.</p>
+<p>The only type of interest for the user is <link id="TElfMachineType"/>.</p>
+</descr>
+
+<!-- enumeration type Visibility: default -->
+<element name="TElfMachineType">
+<short>Enumeration for ELF machine type</short>
+<descr>
+<p>This enumeration specifies the ELF machine type.</p>
+<p>It is used by <link id="elfwriter.TElfResourceWriter">TElfResourceWriter</link> to specify the machine type of the generated object file and by <link id="elfreader.TElfResourceReader">TElfResourceReader</link> to read the machine type of the object file that has been read.</p>
+</descr>
+<seealso>
+<link id="elfwriter.TElfResourceWriter.MachineType">TElfResourceWriter.MachineType</link>
+<link id="elfreader.TElfResourceReader.MachineType">TElfResourceReader.MachineType</link>
+</seealso>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtnone">
+<short>Invalid machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtsparc">
+<short>Sparc machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emti386">
+<short>Intel 386 machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtm68k">
+<short>Motorola 68000 machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtppc">
+<short>PowerPC machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtppc64">
+<short>PowerPC 64 machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtarm">
+<short>ARM machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtarmeb">
+<short>ARM Big Endian machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtia64">
+<short>Intel IA-64 machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtx86_64">
+<short>AMD x86_64 machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TElfMachineType.emtalpha">
+<short>DEC Alpha machine type</short>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFMAGIC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFCLASSNONE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFCLASS32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFCLASS64">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFDATANONE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFDATA2LSB">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFDATA2MSB">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EV_NONE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EV_CURRENT">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFOSABI_NONE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFOSABI_LINUX">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFOSABI_FREEBSD">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ELFOSABI_ARM">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_NONE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_REL">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_EXEC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_DYN">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_CORE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_LOOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_HIOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_LOPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ET_HIPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_NONE">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_SPARC">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_386">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_68K">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_PPC">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_PPC64">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_ARM">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_IA_64">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_X86_64">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EM_ALPHA">
+<short></short>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EF_IA_64_ABI64">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_NULL">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_PROGBITS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_SYMTAB">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_STRTAB">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_RELA">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_HASH">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_DYNAMIC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_NOTE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_NOBITS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_REL">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_SHLIB">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_DYNSYM">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_LOPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_HIPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_LOOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHT_HIOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHF_WRITE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHF_ALLOC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHF_EXECINSTR">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHF_MASKOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="SHF_MASKPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STB_LOCAL">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STB_GLOBAL">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STB_WEAK">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STB_LOOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STB_HIOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STB_LOPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STB_HIPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_NOTYPE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_OBJECT">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_FUNC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_SECTION">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_FILE">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_COMMON">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_TLS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_LOOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_HIOS">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_LOPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_SPARC_REGISTER">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="STT_HIPROC">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_386_32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_x86_64_64">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_PPC_ADDR32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_PPC64_ADDR64">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_ARM_ABS32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_68K_32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_SPARC_32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_ALPHA_REFQUAD">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="R_IA64_DIR64LSB">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+</module> <!-- elfconsts -->
+
+</package>
+</fpdoc-descriptions>

+ 111 - 0
packages/fcl-res/xml/elfreader.xml

@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    elfreader
+  ====================================================================
+-->
+
+<module name="elfreader">
+<short>Contains a resource reader for ELF files</short>
+<descr>
+<p>This unit contains <link id="TElfResourceReader"/>, a <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link> descendant that is able to read ELF object files containing resources.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TElfResourceReader"/> with <link id="resource.TResources">TResources</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="elfconsts">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="elftypes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="elfcommon">
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceReaderException">
+<short>Base class for elf resource reader-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceReaderUnknownClassException">
+<short>Unknown ELF class error</short>
+<descr>
+<p>This exception is raised by <link id="resource.TAbstractResourceReader.Load">Load</link> method of <link id="TElfResourceReader"/> when class field of ELF header is neither <link id="elfconsts.ELFCLASS32">ELFCLASS32</link> nor <link id="elfconsts.ELFCLASS64">ELFCLASS64</link>.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceReaderUnknownVersionException">
+<short>Unknown ELF version error</short>
+<descr>
+<p>This exception is raised by <link id="resource.TAbstractResourceReader.Load">Load</link> method of <link id="TElfResourceReader"/> when version field of ELF header is not 1.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceReaderNoSectionsException">
+<short>No section headers error</short>
+<descr>
+<p>This exception is raised by <link id="resource.TAbstractResourceReader.Load">Load</link> method of <link id="TElfResourceReader"/> when no section headers are found.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceReaderNoStringTableException">
+<short>No string table error</short>
+<descr>
+<p>This exception is raised by <link id="resource.TAbstractResourceReader.Load">Load</link> method of <link id="TElfResourceReader"/> when no ELF string table is found.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TElfResourceReader">
+<short>ELF resource reader</short>
+<descr>
+<p>This class provides a reader for ELF object files and images containing resources.</p>
+<p>ELF is the file format used by unices and other operating systems for object files and image files (executables, dynamic libraries and so on). Free Pascal can store resources in ELF files in its own format.</p>
+<p>After an object file has been read, <link id="TElfResourceReader.MachineType">MachineType</link> property holds the machine type the object file was built for.</p>
+<remark>This reader can't read ELF files without section headers. These are however very rare.</remark>
+</descr>
+<seealso>
+<link id="TElfResourceReader.MachineType"/>
+<link id="resource.TAbstractResourceReader">TAbstractResourceReader</link>
+<link id="elfwriter.TElfResourceWriter">TElfResourceWriter</link>
+<link id="Format of resources in object files"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TElfResourceReader.MachineType">
+<short>The machine type of the object file</short>
+<descr>
+<p>This property holds the machine type of the object file that has been read.</p>
+<remark>Obviously, this property is meaningful only after an object file has been read.</remark>
+</descr>
+<seealso>
+<link id="elfconsts.TElfMachineType">TElfMachineType</link>
+</seealso>
+</element>
+
+</module> <!-- elfreader -->
+
+</package>
+</fpdoc-descriptions>

+ 106 - 0
packages/fcl-res/xml/elfwriter.xml

@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    elfwriter
+  ====================================================================
+-->
+
+<module name="elfwriter">
+<short>Contains a resource writer for ELF files</short>
+<descr>
+<p>This unit contains <link id="TElfResourceWriter"/>, a <link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link> descendant that is able to write ELF object files containing resources.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TElfResourceWriter"/> with <link id="resource.TResources">TResources</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="elfconsts">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="elftypes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="elfcommon">
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceWriterException">
+<short>Base class for elf resource writer-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceWriterUnknownMachineException">
+<short>Unknown machine type error</short>
+<descr>
+<p>This exception is raised when an attempt is made to set <link id="elfwriter.TElfResourceWriter.MachineType">TElfResourceWriter.MachineType</link> to an unknown machine type.</p>
+</descr>
+<seealso>
+<link id="elfwriter.TElfResourceWriter.MachineType">TElfResourceWriter.MachineType</link>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceWriterUnknownClassException">
+<short>Internal error</short>
+<descr>
+<p>If this exception is raised, an internal error occurred.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EElfResourceWriterUnknownSectionException">
+<short>Internal error</short>
+<descr>
+<p>If this exception is raised, an internal error occurred.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TElfResourceWriter">
+<short>ELF resource writer</short>
+<descr>
+<p>This class provides a writer for ELF object files and images containing resources.</p>
+<p>ELF is the file format used by unices and other operating systems for object files and image files (executables, dynamic libraries and so on). Free Pascal can store resources in ELF files in its own format.</p>
+<p><link id="TElfResourceWriter.MachineType">MachineType</link> property can be used to set the machine type of the object file to generate.</p>
+</descr>
+<seealso>
+<link id="TElfResourceWriter.MachineType"/>
+<link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link>
+<link id="elfreader.TElfResourceReader">TElfResourceReader</link>
+<link id="Format of resources in object files"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TElfResourceWriter.MachineType">
+<short>The machine type of the object file</short>
+<descr>
+<p>This property can be used to set the machine type of the object file to write.</p>
+<p>If an attempt is made to set MachineType to an unsupported value, an <link id="EElfResourceWriterUnknownMachineException"/> exception is raised.</p>
+</descr>
+<seealso>
+<link id="elfconsts.TElfMachineType">TElfMachineType</link>
+<link id="EElfResourceWriterUnknownMachineException"/>
+</seealso>
+</element>
+
+</module> <!-- elfwriter -->
+
+</package>
+</fpdoc-descriptions>

+ 73 - 0
packages/fcl-res/xml/externalreader.xml

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    externalreader
+  ====================================================================
+-->
+
+<module name="externalreader">
+<short>Contains a resource reader for external resource files</short>
+<descr>
+<p>This unit contains <link id="TExternalResourceReader"/>, a <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link> descendant that is able to read standalone resource files in a Free Pascal-specific format.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TExternalResourceReader"/> with <link id="resource.TResources">TResources</link>.</p>
+<p><b>See also</b></p>
+<p><link id="externaltypes.Free Pascal external resource file format description">Free Pascal external resource file format description</link></p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resourcetree">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="externaltypes">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TExternalResourceReader">
+<short>External file resource reader</short>
+<descr>
+<p>This class provides a reader for .fpcres files: they are standalone files containing resources.</p>
+<p>Standalone files are files that don't get linked with the final executable. They are used as a
+fallback solution on all those platforms for which an internal resource format is not available.</p>
+<p>At runtime the resource file is read by Free Pascal RTL to provide resource support to the application.</p>
+<p>After an external file has been read, <link id="TExternalResourceReader.Endianess">Endianess</link> property holds the byte order used in the file.</p>
+</descr>
+<seealso>
+<link id="TExternalResourceReader.Endianess"/>
+<link id="resource.TAbstractResourceReader">TAbstractResourceReader</link>
+<link id="externalwriter.TExternalResourceWriter">TExternalResourceWriter</link>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TExternalResourceReader.Endianess">
+<short>The byte order used in the file</short>
+<descr>
+<p>This property holds the byte order (endianess) of the file that has been read.</p>
+<remark>Obviously, this property is meaningful only after a file has been read.</remark>
+</descr>
+<seealso>
+<link id="externaltypes.EXT_ENDIAN_BIG">EXT_ENDIAN_BIG</link>
+<link id="externaltypes.EXT_ENDIAN_LITTLE">EXT_ENDIAN_LITTLE</link>
+</seealso>
+</element>
+
+</module> <!-- externalreader -->
+
+</package>
+</fpdoc-descriptions>

+ 311 - 0
packages/fcl-res/xml/externaltypes.xml

@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    externaltypes
+  ====================================================================
+-->
+
+<module name="externaltypes">
+<short>Contains types and constants used by external resource reader and writer</short>
+<descr>
+<p>These types are used internally by <link id="externalreader.TExternalResourceReader">TExternalResourceReader</link> and <link id="externalwriter.TExternalResourceWriter">TExternalResourceWriter</link>.</p>
+<p>Two constants are of interest: <link id="EXT_ENDIAN_BIG"/> and <link id="EXT_ENDIAN_LITTLE"/>.</p>
+</descr>
+
+<topic name="Description of external resource file format">
+<short>Description of external resource file format</short>
+<descr>
+<p><b>Introduction</b></p>
+<p>An external resource file (.fpcres extension) provides resource support for those systems where a resource format suitable to be embedded in an object file isn't available.</p>
+<p>The file format is designed in a way similar to other internal resource formats. The file is opened at program startup and is mapped in the program address space. Offsets in the file are easily converted to pointers at runtime since those offsets represent a displacement from a base address (the starting address where the file is mapped). Differences from an internal file format hence lie in the fact that resources aren't mapped in the program address space by the program loader but by Free Pascal RTL, and data must be accessed with a displacement mechanism instead of absolute pointers.</p>
+<p>For internal resources details, see <link id ="Format of resources in object files"/></p>
+<p><b>File layout</b></p>
+<p>An external resource file consists of these parts:</p>
+<ul>
+<li>The initial header, containing various file information</li>
+<li>The resource tree, in the form of nodes</li>
+<li>The string table, which can be optional</li>
+<li>The resource data</li>
+</ul>
+<p>The header is made up by initial header, resource tree and string table (if present).</p>
+<p><b>Conventions</b></p>
+<p>In this document, data sizes are specified with pascal-style data types. They are the following:</p>
+<table>
+<th><td>Name</td><td>Meaning</td></th>
+<tr><td><var>byte</var></td><td>Unsigned 8 bit integer.</td></tr>
+<tr><td><var>longword</var></td><td>Unsigned 32 bit integer.</td></tr>
+<tr><td><var>qword</var></td><td>Unsigned 64 bit integer.</td></tr>
+</table>
+<p>Byte order used in the file is specified in the initial header.</p>
+<p>All data structures in the file must be aligned on qword boundaries.</p>
+
+<p><b>The initial header</b></p>
+<p>An external resource file starts with this header:</p>
+<table>
+	<th><td>Name</td><td>Offset</td><td>Length</td><td>Description</td></th>
+ 	<tr>
+		<td>magic</td>
+		<td>0</td>
+		<td>6</td>
+		<td>Six ASCII characters that form the string <var>FPCRES</var></td>
+	</tr>
+
+	<tr>
+		<td>version</td>
+		<td>6</td>
+		<td>byte</td>
+		<td>File format version. Currently it is <var>1</var>.</td>
+	</tr>
+	<tr>
+		<td>endianess</td>
+		<td>7</td>
+		<td>byte</td>
+		<td>Byte order. <var>1</var> for big endian, <var>2</var> for little endian</td>
+	</tr>
+	<tr>
+		<td>count</td>
+		<td>8</td>
+		<td>longword</td>
+		<td>Number of resources in the file</td>
+	</tr>
+	<tr>
+		<td>nodesize</td>
+		<td>12</td>
+		<td>longword</td>
+		<td>Size of header up to the string table, excluded</td>
+	</tr>
+	<tr>
+		<td>hdrsize</td>
+		<td>16</td>
+		<td>longword</td>
+		<td>Full size of header (up to the string table, included)</td>
+	</tr>
+	<tr>
+		<td>reserved</td>
+		<td>20</td>
+		<td>12</td>
+		<td>Must be zero</td>
+	</tr>
+</table>
+<p>Note that byte order of the file can be read in the <var>endianess</var> field of the header. All data fields longer than a byte are written with the byte order specified in <var>endianess</var>.</p>
+<p>If no resource name or type is identified by strings, string table is optional. When this is the case, <var>nodesize</var> and <var>hdrsize</var> have the same value.</p>
+
+<p><b>The resource tree</b></p>
+<p>Immediately following the initial header, the resource tree comes. It is made up by nodes that represent resource types, names and language ids.</p>
+<p>Data is organized so that resource information (type, name and language id) is represented by a tree: root node contains resource types, that in turn contain resource names, which contain language ids, which describe resource data.</p>
+<p>Given a node, its sub-nodes are ordered as follows:</p>
+<ul>
+<li>First the "named" nodes (nodes that use a string as identifier) come, then the id ones (nodes that use an integer as identifier).</li>
+<li>Named nodes are alphabetically sorted, in ascending order.</li>
+<li>Id nodes are sorted in ascending order.</li>
+</ul>
+<p>In the file, all sub-nodes of a node are written in the order described above. Then, all sub-nodes of the first sub-node are written, and so on.</p>
+<p><b>Example:</b></p>
+<p>There are three resources:</p>
+<ol>
+<li>a <var>BITMAP</var> resource with name <var>MYBITMAP</var> and language id <var>$0409</var></li>
+<li>a <var>BITMAP</var> resource with name <var>1</var> and language id <var>0</var></li>
+<li>a resource with type <var>MYTYPE</var> and name <var>1</var> and language id <var>0</var></li>
+</ol>
+<p>Nodes are laid out this way (note that <var>BITMAP</var> resources have type <var>2</var>):</p>
+<pre>
+ 
+root | MYTYPE 2 | 1 | 0 | MYBITMAP 1 | $0409 | 0
+</pre>
+<p>That is, types (<var>MYTYPE</var> is a string, so it comes before <var>2</var> which is <var>BITMAP</var>), then names for <var>MYTYPE</var> (<var>1</var>), then language id for resource 3 (<var>0</var>), then names for <var>BITMAP</var> (<var>MYBITMAP</var> and <var>1</var>), then language id for resource 1 (<var>$0409</var>), then language id for resource 2 (<var>0</var>).</p>
+
+<p><b>Node format</b></p>
+<table>
+	<th><td>Name</td><td>Offset</td><td>Length</td><td>Description</td></th>
+	<tr>
+		<td>nameid</td>
+		<td>0</td>
+		<td>longword</td>
+		<td>name offset, integer id or language id</td>
+	</tr>
+	<tr>
+		<td>ncount</td>
+		<td>4</td>
+		<td>longword</td>
+		<td>named sub-nodes count</td>
+	</tr>
+	<tr>
+		<td>idcountsize</td>
+		<td>8</td>
+		<td>longword</td>
+		<td>id sub-nodes count or resource size</td>
+	</tr>
+	<tr>
+		<td>subptr</td>
+		<td>12</td>
+		<td>longword</td>
+		<td>offset to first sub-node</td>
+	</tr>
+</table>
+<p>Note that all offset are always relative to the beginning of the file.</p>
+<p>If the node is identified by a string, <var>nameid</var> is an offset to the null-terminated string holding the name. If it is identified by an id, <var>nameid</var> is that id. Language id nodes are always identified by and ID.</p>
+<p><var>ncount</var> is the number of named sub-nodes of this node (nodes that are identified by a string).</p>
+<p><var>idcountsize</var> is the number of id sub-nodes of this node (nodes that are identified by an integer id). For language id nodes, this field holds the size of the resource data.</p>
+<p><var>subptr</var> is an offset to the first subnode of this node. Note that it allows to access every subnode of this node, since subnodes of a node always come one after the other. For language id nodes, <var>subptr</var> is the offset to the resource data.</p>
+
+<p><b>The string table</b></p>
+<p>The string table is used to store strings used for resource types and names. If all resources use integer ids for name and types, it may not be present in the file.</p>
+<p>The string table simply contains null-terminated strings, one after the other.</p>
+<p>If present, the string table always contains a <var>0</var> (zero) at the beginning. This way, the empty string is located at the offset of the string table (whose value is held in <var>nodesize</var> field of the initial header).</p>
+
+<p><b>The resource data</b></p>
+<p>This part of the file contains raw resource data. As written before, all data structures must be aligned on qword boundaries, so if a resource data size is not a multiple of 8, bytes of padding must be inserted after that resource data.</p>
+</descr>
+</topic>
+
+<!-- array type Visibility: default -->
+<element name="TExternalResMagic">
+<short>Type used for the magic identifier in external resource files</short>
+<seealso>
+<link id="EXTERNAL_RESMAGIC"/>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TExtHeader">
+<short>Header of an external resource file</short>
+<descr>
+<p>This header describes the data structure present at the beginning of an external resource file.</p>
+</descr>
+<seealso>
+<link id="EXTERNAL_RESMAGIC"/>
+<link id="EXT_CURRENT_VERSION"/>
+<link id="EXT_ENDIAN_BIG"/>
+<link id="EXT_ENDIAN_LITTLE"/>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.magic">
+<short>String identifying the file format</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.version">
+<short>File format version</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.endianess">
+<short>Byte order of the file</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.count">
+<short>Number of resources in the file</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.nodesize">
+<short>Size of header up to string table, excluded</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.hdrsize">
+<short>Size of header up to string table, included</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.reserved1">
+<short>Unused as of version 1</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.reserved2">
+<short>Unused as of version 1</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TExtHeader.reserved3">
+<short>Unused as of version 1</short>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TResInfoNode">
+<short>A node of a resource tree</short>
+<descr>
+<p>This record represents a node used in a resource tree. A node contains information about a certain resource type, name or language id.</p>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TResInfoNode.nameid">
+<short>Name or ID of the node</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TResInfoNode.ncount">
+<short>Number of named sub-entries</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TResInfoNode.idcountsize">
+<short>Number of ID sub-entries or resource size</short>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TResInfoNode.subptr">
+<short>Offset to first subnode or resource data</short>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EXTERNAL_RESMAGIC">
+<short>Magic identifier for the external resource file type</short>
+<descr>
+<p>This value is used for <link id="TExtHeader.magic"/>.</p>
+</descr>
+<seealso>
+<link id="TExternalResMagic"/>
+<link id="TExtHeader"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EXT_CURRENT_VERSION">
+<short>Current version of file format</short>
+<descr>
+<p>This value is used for <link id="TExtHeader.version"/>.</p>
+</descr>
+<seealso>
+<link id="TExtHeader"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EXT_ENDIAN_BIG">
+<short>The file uses big endian byte order</short>
+<descr>
+<p>This value is used for <link id="TExtHeader.endianess"/>.</p>
+</descr>
+<seealso>
+<link id="TExtHeader"/>
+<link id="EXT_ENDIAN_LITTLE"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="EXT_ENDIAN_LITTLE">
+<short>The file uses little endian byte order</short>
+<descr>
+<p>This value is used for <link id="TExtHeader.endianess"/>.</p>
+</descr>
+<seealso>
+<link id="TExtHeader"/>
+<link id="EXT_ENDIAN_BIG"/>
+</seealso>
+</element>
+
+</module> <!-- externaltypes -->
+
+</package>
+</fpdoc-descriptions>

+ 97 - 0
packages/fcl-res/xml/externalwriter.xml

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    externalwriter
+  ====================================================================
+-->
+
+<module name="externalwriter">
+<short>Contains a resource writer for external resource files</short>
+<descr>
+<p>This unit contains <link id="TExternalResourceWriter"/>, a <link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link> descendant that is able to write standalone resource files in a Free Pascal-specific format.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TExternalResourceWriter"/> with <link id="resource.TResources">TResources</link>.</p>
+<p><b>See also</b></p>
+<p><link id="externaltypes.Free Pascal external resource file format description">Free Pascal external resource file format description</link></p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resourcetree">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="externaltypes">
+</element>
+
+<!-- object Visibility: default -->
+<element name="EExternalResourceWriterException">
+<short>Base class for external resource writer-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EExternalResInvalidEndianessException">
+<short>Invalid endianess error</short>
+<descr>
+<p>This exception is raised when an attempt is made to set <link id="TExternalResourceWriter.Endianess">Endianess</link> property of a <link id="TExternalResourceWriter"/> object to a value other than <link id="externaltypes.EXT_ENDIAN_BIG">EXT_ENDIAN_BIG</link> or <link id="externaltypes.EXT_ENDIAN_LITTLE">EXT_ENDIAN_LITTLE</link>.</p>
+</descr>
+<seealso>
+<link id="TExternalResourceWriter.Endianess"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TExternalResStringTable">
+<short>External resource file string table</short>
+<descr>
+<p>This class is used internally by <link id="TExternalResourceWriter"/>.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TExternalResourceWriter">
+<short>External file resource writer</short>
+<descr>
+<p>This class provides a writer for .fpcres files: they are standalone files containing resources.</p>
+<p>Standalone files are files that don't get linked with the final executable. They are used as a
+fallback solution on all those platforms for which an internal resource format is not available.</p>
+<p>At runtime the resource file is read by Free Pascal RTL to provide resource support to the application.</p>
+<p><link id="TExternalResourceWriter.Endianess">Endianess</link> property can be used to set the byte order to use in the file to generate.</p>
+</descr>
+<seealso>
+<link id="TExternalResourceWriter.Endianess"/>
+<link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link>
+<link id="externalreader.TExternalResourceReader">TExternalResourceReader</link>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TExternalResourceWriter.Endianess">
+<short>The byte order to use in the file</short>
+<descr>
+<p>This property can be used to set the byte order (endianess) of the file to write.</p>
+<remark>If a value other than <link id="externaltypes.EXT_ENDIAN_BIG">EXT_ENDIAN_BIG</link> or <link id="externaltypes.EXT_ENDIAN_LITTLE">EXT_ENDIAN_LITTLE</link> is used, an <link id="EExternalResInvalidEndianessException"/> exception is raised.</remark>
+</descr>
+<seealso>
+<link id="externaltypes.EXT_ENDIAN_BIG">EXT_ENDIAN_BIG</link>
+<link id="externaltypes.EXT_ENDIAN_LITTLE">EXT_ENDIAN_LITTLE</link>
+</seealso>
+</element>
+
+</module> <!-- externalwriter -->
+
+</package>
+</fpdoc-descriptions>

+ 134 - 0
packages/fcl-res/xml/fpdoc.css

@@ -0,0 +1,134 @@
+/*
+  $Id: fpdoc.css,v 1.1 2003/03/17 23:03:20 michael Exp $
+
+  Default style sheet for FPDoc reference documentation
+  by Sebastian Guenther, [email protected]
+
+  Feel free to use this file as a template for your own style sheets.
+*/
+
+body {
+  background: white
+}
+
+body, p, th, td, caption, h1, h2, h3, ul, ol, dl {
+  color: black;
+  font-family: sans-serif
+}
+
+tt, span.kw, pre {
+  font-family: Courier, monospace
+}
+
+body, p, th, td, caption, ul, ol, dl, tt, span.kw, pre {
+  font-size: 14px
+}
+
+A:link {
+  color: blue
+}
+
+A:visited {
+  color: darkblue
+}
+
+A:active {
+  color: red
+}
+
+A {
+  text-decoration: none
+}
+
+A:hover {
+  text-decoration: underline
+}
+
+h1, h2, td.h2 {
+  color: #005A9C
+}
+
+/* Especially for Netscape on Linux: */
+h3, td.h3 {
+  font-size: 12pt
+}
+
+/* source fragments */
+span.code {
+  white-space: nowrap
+}
+
+/* symbols in source fragments */
+span.sym {
+  color: darkred
+}
+
+/* keywords in source fragments */
+span.kw {
+  font-weight: bold
+}
+
+/* comments in source fragments */
+span.cmt {
+  color: darkcyan;
+  font-style: italic
+}
+
+/* directives in source fragments */
+span.dir {
+  color: darkyellow;
+  font-style: italic
+}
+
+/* numbers in source fragments */
+span.num {
+  color: darkmagenta
+}
+
+/* characters (#...) in source fragments */
+span.chr {
+  color: darkcyan
+}
+
+/* strings in source fragments */
+span.str {
+  color: blue
+}
+
+/* assembler passages in source fragments */
+span.asm {
+  color: green
+}
+
+
+td.pre {
+  white-space: pre
+}
+
+p.cmt {
+  color: gray
+}
+
+span.warning {
+  color: red;
+  font-weight: bold
+}
+
+/* !!!: How should we define this...? */
+span.file {
+  color: darkgreen
+}
+
+table.remark {
+  background-color: #ffffc0;
+}
+
+table.bar {
+  background-color: #a0c0ff;
+}
+
+span.bartitle {
+  font-weight: bold;
+  font-style: italic;
+  color: darkblue
+}

+ 71 - 0
packages/fcl-res/xml/groupcursorresource.xml

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    groupcursorresource
+  ====================================================================
+-->
+
+<module name="groupcursorresource">
+<short>Contains a group cursor resource type</short>
+<descr>
+<p>This unit contains <link id="TGroupCursorResource"/>, a <link id="resource.TAbstractResource">TAbstractResource</link> descendant specialized in handling resource of type <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link>.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TGroupCursorResource"/> for type <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link> with <link id="resfactory.TResourceFactory">TResourceFactory</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="groupresource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TGroupCursorResource">
+<short>Group cursor resource type</short>
+<descr>
+<p>This class represents a resource of type <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link>.</p>
+<p>Resources of this type are strictly related to .cur files: typically a resource compiler creates resources of this type when it is instructed to insert a cursor from a .cur file.</p>
+<p>There is although a big difference between .cur files and cursor resources: a .cur file contains a cursor, which is made of several different images (for different sizes and color depth), but while a file of this type is self-contained, when it comes to resources data is scattered over several different resources: an <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link> resource only contains information about the single images, which are contained each in a different resource of type <link id="resource.RT_CURSOR">RT_CURSOR</link>. The single resources are pretty unuseful alone, since they only consist of raw image data: they must be accessed in the contest of the <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link> resource, which provides information about them.</p>
+<p><link id="TGroupCursorResource"/> provides a way to handle a cursor as if it was a .cur file, via <link id="groupresource.TGroupResource.ItemData">ItemData</link> property. Single cursor resources are automatically created or destroyed as needed.</p>
+<remark>This class doesn't allow its type to be changed to anything else than <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link>. Attempts to do so result in a <link id="resource.EResourceDescChangeNotAllowedException">EResourceDescChangeNotAllowedException</link>.</remark>
+</descr>
+<seealso>
+<link id="groupresource.TGroupResource.ItemData">TGroupResource.ItemData</link>
+<link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>
+</seealso>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TGroupCursorResource.Create">
+<short>Creates a new group cursor resource</short>
+<descr>
+<p>Please note that <var>aType</var> parameter is not used, since this class always uses <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link> as type.</p>
+</descr>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TGroupCursorResource.Create.aType">
+<short>Ignored. Can be <var>nil</var>.</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TGroupCursorResource.Create.aName">
+<short>The name of the resource</short>
+</element>
+
+</module> <!-- groupcursorresource -->
+
+</package>
+</fpdoc-descriptions>

+ 71 - 0
packages/fcl-res/xml/groupiconresource.xml

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    groupiconresource
+  ====================================================================
+-->
+
+<module name="groupiconresource">
+<short>Contains a group icon resource type</short>
+<descr>
+<p>This unit contains <link id="TGroupIconResource"/>, a <link id="resource.TAbstractResource">TAbstractResource</link> descendant specialized in handling resource of type <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link>.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TGroupIconResource"/> for type <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> with <link id="resfactory.TResourceFactory">TResourceFactory</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="groupresource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TGroupIconResource">
+<short>Group icon resource type</short>
+<descr>
+<p>This class represents a resource of type <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link>.</p>
+<p>Resources of this type are strictly related to .ico files: typically a resource compiler creates resources of this type when it is instructed to insert an icon from an .ico file.</p>
+<p>There is although a big difference between .ico files and icon resources: an .ico file contains an icon, which is made of several different images (for different sizes and color depth), but while a file of this type is self-contained, when it comes to resources data is scattered over several different resources: an <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> resource only contains information about the single images, which are contained each in a different resource of type <link id="resource.RT_ICON">RT_ICON</link>. The single resources are pretty unuseful alone, since they only consist of raw image data: they must be accessed in the contest of the <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> resource, which provides information about them.</p>
+<p><link id="TGroupIconResource"/> provides a way to handle an icon as if it was a .ico file, via <link id="groupresource.TGroupResource.ItemData">ItemData</link> property. Single icon resources are automatically created or destroyed as needed.</p>
+<remark>This class doesn't allow its type to be changed to anything else than <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link>. Attempts to do so result in a <link id="resource.EResourceDescChangeNotAllowedException">EResourceDescChangeNotAllowedException</link>.</remark>
+</descr>
+<seealso>
+<link id="groupresource.TGroupResource.ItemData">TGroupResource.ItemData</link>
+<link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>
+</seealso>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TGroupIconResource.Create">
+<short>Creates a new group icon resource</short>
+<descr>
+<p>Please note that <var>aType</var> parameter is not used, since this class always uses <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> as type.</p>
+</descr>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TGroupIconResource.Create.aType">
+<short>Ignored. Can be <var>nil</var>.</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TGroupIconResource.Create.aName">
+<short>The name of the resource</short>
+</element>
+
+</module> <!-- groupiconresource -->
+
+</package>
+</fpdoc-descriptions>

+ 144 - 0
packages/fcl-res/xml/groupresource.xml

@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    groupresource
+  ====================================================================
+-->
+
+<module name="groupresource">
+<short>Contains group resource classes</short>
+<descr>
+<p>This unit contains <link id="TGroupResource"/> and <link id="TGroupCachedDataStream"/>, two classes used for resources of type <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> and <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link>.</p>
+<p>The former is an abstract resource class which is implemented by <link id="groupiconresource.TGroupIconResource">TGroupIconResource</link> and <link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>, and the latter is a <link id="resdatastream.TCachedDataStream">TCachedDataStream</link> descendant used to provide .ico/.cur like streams for resource classes mentioned earlier.</p>
+<p>This unit shouldn't be of interest for the user, who should look at documentation for <link id="groupiconresource"/> and <link id="groupcursorresource"/> units instead.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resdatastream">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TGroupResource">
+<short>Abstract common class for group icon and group cursor classes</short>
+<descr>
+<p>This class provides common functionalities that are extended by <link id="groupiconresource.TGroupIconResource">TGroupIconResource</link> and <link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>.</p>
+<p>Resources of type <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> and <link id="resource.RT_GROUP_CURSOR">RT_GROUP_CURSOR</link> represent a .ico or .cur file, respectively. However, data isn't contained in a single resource, but it's scattered over several different resources. That is, a .ico file contains an icon, which is made of several different images (for different sizes and color depth); when it is represented as a resource, however, the <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> resource only contains information about the single images, which are contained each in a different resource of type <link id="resource.RT_ICON">RT_ICON</link>. The single resources are pretty unuseful alone, since they only consist of raw image data: they must be accessed in the contest of the <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> resource, which provides information about them.</p>
+<p><link id="groupiconresource.TGroupIconResource">TGroupIconResource</link> and <link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link> provide a way to handle resources of these types as if they were .ico or .cur files. This class implements common functionalities, since icons and cursors are very similar.</p>
+<remark>An object of this class should never be directly instantiated: use a descendant class instead.</remark>
+</descr>
+<seealso>
+<link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>
+<link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>
+</seealso>
+</element>
+
+<!-- destructor Visibility: public -->
+<element name="TGroupResource.Destroy">
+<short></short>
+<descr>
+</descr>
+<errors>
+</errors>
+<seealso>
+</seealso>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TGroupResource.SetCustomItemDataStream">
+<short>Sets a custom stream as the underlying stream for ItemData</short>
+<descr>
+<p>This method allows the user to use a custom stream as the underlying stream for <link id="TGroupResource.ItemData">ItemData</link>. This is useful when you want a <link id="groupiconresource.TGroupIconResource">TGroupIconResource</link> or <link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link> to be created from a ico or cur file for which you have a stream.</p>
+<p><b>Sample code</b></p>
+<p>This code creates a resource containing an icon</p>
+<code>
+var
+  aName : TResourceDesc;
+  aRes : TGroupIconResource;
+  aFile : TFileStream;
+  Resources : TResources;
+begin
+  Resources:=TResources.Create;
+  aName:=TResourceDesc.Create('MAINICON');
+  aRes:=TGroupIconResource.Create(nil,aName); //type is always RT_GROUP_ICON
+  aName.Free; //not needed anymore
+  aFile:=TFileStream.Create('mainicon.ico',fmOpenRead or fmShareDenyNone);
+  aRes.SetCustomItemDataStream(aFile);
+  Resources.Add(aRes);
+  Resources.WriteToFile('myresource.res');
+
+  Resources.Free; //it destroys aRes as well.
+  aFile.Free;
+end;
+</code>
+
+
+</descr>
+<errors>
+</errors>
+<seealso>
+<link id="TGroupResource.ItemData"/>
+<link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>
+<link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>
+<link id="resource.TAbstractResource.UpdateRawData">TAbstractResource.UpdateRawData</link>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TGroupResource.SetCustomItemDataStream.aStream">
+<short>The custom stream to use as the underlying ItemData stream</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TGroupResource.ItemData">
+<short>Resource data as an ICO/CUR stream</short>
+<descr>
+<p>This property gives access to resource data in a (ICO or CUR) file-like stream, unlike <link id="resource.TAbstractResource.RawData">RawData</link>.</p>
+<p>The exact format of the stream (ico or cur) is determined by the descendant class of <link id="TGroupResource"/> that is used.</p>
+<p>ItemData does not create a copy of <link id="resource.TAbstractResource.RawData">RawData</link> so memory usage is generally kept limited.</p>
+<p>You can also set a custom stream as the underlying stream for ItemData via <link id="TGroupResource.SetCustomItemDataStream">SetCustomItemDataStream</link>, much like <link id="resource.TAbstractResource.SetCustomRawDataStream">SetCustomRawDataStream</link> does for <link id="resource.TAbstractResource.RawData">RawData</link>. This is useful when you want a <link id="groupiconresource.TGroupIconResource">TGroupIconResource</link> or <link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link> to be created from a ico or cur file for which you have a stream.</p>
+<remark>If you need to access <link id="resource.TAbstractResource.RawData">RawData</link> after you modified ItemData, be sure to call <link id="resource.TAbstractResource.UpdateRawData">UpdateRawData</link> first. This isn't needed however when resource is written to a stream, since <link id="resource.TResources">TResources</link> takes care of it.</remark>
+</descr>
+<seealso>
+<link id="TGroupResource.SetCustomItemDataStream"/>
+<link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>
+<link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>
+<link id="resource.TAbstractResource.RawData">TAbstractResource.RawData</link>
+<link id="resource.TAbstractResource.UpdateRawData">TAbstractResource.UpdateRawData</link>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TGroupCachedDataStream">
+<short>Cached stream for group classes</short>
+<descr>
+<p>This class is used by <link id="TGroupResource"/> descendants to provide an .ico/.cur like stream.</p>
+<p>Unlike <link id="resdatastream.TCachedResourceDataStream">TCachedResourceDataStream</link>, which provides a stream-like interface over a portion of another stream, this class lets multiple stream to be seen as one: this way, several <link id="resource.RT_ICON">RT_ICON</link> or <link id="resource.RT_CURSOR">RT_CURSOR</link> resources can appear like a single .ico or .cur file.</p>
+</descr>
+<seealso>
+<link id="TGroupResource"/>
+<link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>
+<link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>
+<link id="resdatastream.TCachedDataStream">TCachedDataStream</link>
+<link id="resdatastream.TCachedResourceDataStream">TCachedResourceDataStream</link>
+</seealso>
+</element>
+
+</module> <!-- groupresource -->
+
+</package>
+</fpdoc-descriptions>

+ 66 - 0
packages/fcl-res/xml/machoreader.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    machoreader
+  ====================================================================
+-->
+
+<module name="machoreader">
+<short>Contains a resource reader for Mach-O files</short>
+<descr>
+<p>This unit contains <link id="TMachOResourceReader"/>, a <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link> descendant that is able to read Mach-O object files containing resources.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TMachOResourceReader"/> with <link id="resource.TResources">TResources</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="machotypes">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TMachOResourceReader">
+<short>Mach-O resource reader</short>
+<descr>
+<p>This class provides a reader for Mach-O object files and images containing resources.</p>
+<p>Mach-O is the file format used by Darwin and Mac OS X for object files and image files (executables, dynamic libraries and so on). Free Pascal can store resources in Mach-O files in its own format.</p>
+<p>After an object file has been read, <link id="TMachOResourceReader.MachineType">MachineType</link> property holds the machine type the object file was built for.</p>
+<remark>This reader can't read multiple-architecture Mach-O files (like universal binary). To read a particular Mach-O file in a multiple-architecture file, extract it with lipo command.</remark>
+</descr>
+<seealso>
+<link id="TMachOResourceReader.MachineType"/>
+<link id="resource.TAbstractResourceReader">TAbstractResourceReader</link>
+<link id="machowriter.TMachOResourceWriter">TMachOResourceWriter</link>
+<link id="Format of resources in object files"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TMachOResourceReader.MachineType">
+<short>The machine type of the object file</short>
+<descr>
+<p>This property holds the machine type of the object file that has been read.</p>
+<remark>Obviously, this property is meaningful only after an object file has been read.</remark>
+</descr>
+<seealso>
+<link id="machotypes.TMachOMachineType">TMachOMachineType</link>
+</seealso>
+</element>
+
+</module> <!-- machoreader -->
+
+</package>
+</fpdoc-descriptions>

+ 945 - 0
packages/fcl-res/xml/machotypes.xml

@@ -0,0 +1,945 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    machotypes
+  ====================================================================
+-->
+
+<module name="machotypes">
+<short>Contains types used by Mach-O reader and writer</short>
+<descr>
+<p>These constants are used internally by <link id="machowriter.TMachOResourceWriter">TMachOResourceWriter</link> and <link id="machoreader.TMachOResourceReader">TMachOResourceReader</link>.</p>
+<p>The only type of interest for the user is <link id="TMachOMachineType"/>.</p>
+</descr>
+
+<!-- enumeration type Visibility: default -->
+<element name="TMachOMachineType">
+<short>Enumeration for Mach-O machine type</short>
+<descr>
+<p>This enumeration specifies the Mach-O machine type.</p>
+<p>It is used by <link id="machowriter.TMachOResourceWriter">TMachOResourceWriter</link> to specify the machine type of the generated object file and by <link id="machoreader.TMachOResourceReader">TMachOResourceReader</link> to read the machine type of the object file that has been read.</p>
+</descr>
+<seealso>
+<link id="machowriter.TMachOResourceWriter.MachineType">TMachOResourceWriter.MachineType</link>
+<link id="machoreader.TMachOResourceReader.MachineType">TMachOResourceReader.MachineType</link>
+</seealso>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TMachOMachineType.mmtpowerpc">
+<short>PowerPC machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TMachOMachineType.mmtpowerpc64">
+<short>PowerPC 64 machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TMachOMachineType.mmti386">
+<short>Intel 386 machine type</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TMachOMachineType.mmtx86_64">
+<short>AMD x86_64 machine type</short>
+</element>
+
+<!-- array type Visibility: default -->
+<element name="TSegSectName">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TMachHdr">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TMachHdr.magic">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TMachHdr.cputype">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TMachHdr.cpusubtype">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TMachHdr.filetype">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TMachHdr.ncmds">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TMachHdr.sizeofcmds">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TMachHdr.flags">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TLoadCommand">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TLoadCommand.cmd">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TLoadCommand.cmdsize">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TSegmentCommand32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.name">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.vmaddr">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.vmsize">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.fileoff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.filesize">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.maxprot">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.initprot">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.nsects">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand32.flags">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TSegmentCommand64">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.name">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.vmaddr">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.vmsize">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.fileoff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.filesize">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.maxprot">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.initprot">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.nsects">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSegmentCommand64.flags">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TSection32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.sectname">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.segname">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.addr">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.size">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.offset">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.align">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.reloff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.nreloc">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.flags">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.reserved1">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection32.reserved2">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TSection64">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.sectname">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.segname">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.addr">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.size">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.offset">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.align">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.reloff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.nreloc">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.flags">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.reserved1">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.reserved2">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSection64.reserved3">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TSymtabCommand">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSymtabCommand.symoff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSymtabCommand.nsyms">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSymtabCommand.stroff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TSymtabCommand.strsize">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TDySymtabCommand">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.ilocalsym">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.nlocalsym">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.iextdefsym">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.nextdefsym">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.iundefsym">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.nundefsym">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.tocoff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.ntoc">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.modtaboff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.nmodtab">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.extrefsymoff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.nextrefsyms">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.indirectsymoff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.nindirectsyms">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.extreloff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.nextrel">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.locreloff">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TDySymtabCommand.nlocrel">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TNList32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList32.strx">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList32._type">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList32.sect">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList32.desc">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList32.value">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- pointer type Visibility: default -->
+<element name="PNList32">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TNList64">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList64.strx">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList64._type">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList64.sect">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList64.desc">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TNList64.value">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- pointer type Visibility: default -->
+<element name="PNList64">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- record type Visibility: default -->
+<element name="TRelocationInfo">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TRelocationInfo.address">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- variable Visibility: default -->
+<element name="TRelocationInfo.flags">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+<!-- pointer type Visibility: default -->
+<element name="PRelocationInfo">
+<short></short>
+<descr>
+</descr>
+<seealso>
+</seealso>
+</element>
+
+</module> <!-- machotypes -->
+
+</package>
+</fpdoc-descriptions>

+ 77 - 0
packages/fcl-res/xml/machowriter.xml

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    machowriter
+  ====================================================================
+-->
+
+<module name="machowriter">
+<short>Contains a resource writer for Mach-O files</short>
+<descr>
+<p>This unit contains <link id="TMachOResourceWriter"/>, a <link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link> descendant that is able to write Mach-O object files containing resources.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TMachOResourceWriter"/> with <link id="resource.TResources">TResources</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="machotypes">
+</element>
+
+<!-- object Visibility: default -->
+<element name="EMachOResourceWriterException">
+<short>Base class for Mach-O resource writer-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EMachOResourceWriterUnknownBitSizeException">
+<short>Internal error</short>
+<descr>
+<p>If this exception is raised, an internal error occurred.</p>
+</descr>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TMachOResourceWriter">
+<short>Mach-O resource writer</short>
+<descr>
+<p>This class provides a writer for Mach-O object files and images containing resources.</p>
+<p>Mach-O is the file format used by Darwin and Mac OS X for object files and image files (executables, dynamic libraries and so on). Free Pascal can store resources in Mach-O files in its own format.</p>
+<p><link id="TMachOResourceWriter.MachineType">MachineType</link> property can be used to set the machine type of the object file to generate.</p>
+</descr>
+<seealso>
+<link id="TMachOResourceWriter.MachineType"/>
+<link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link>
+<link id="machoreader.TMachOResourceReader">TMachOResourceReader</link>
+<link id="Format of resources in object files"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TMachOResourceWriter.MachineType">
+<short>The machine type of the object file</short>
+<descr>
+<p>This property can be used to set the machine type of the object file to write.</p>
+</descr>
+<seealso>
+<link id="machotypes.TMachOMachineType">TMachOMachineType</link>
+</seealso>
+</element>
+
+</module> <!-- machowriter -->
+
+</package>
+</fpdoc-descriptions>

+ 33 - 0
packages/fcl-res/xml/makehtml.sh

@@ -0,0 +1,33 @@
+#!/bin/bash
+fpdoc --package=fcl-res --format=html \
+  --input=../src/resource.pp --descr=resource.xml \
+  --input=../src/resourcetree.pp --descr=resourcetree.xml \
+  --input=../src/resdatastream.pp --descr=resdatastream.xml \
+  --input=../src/resfactory.pp --descr=resfactory.xml \
+  --input=../src/resreader.pp --descr=resreader.xml \
+  --input=../src/reswriter.pp --descr=reswriter.xml \
+  --input=../src/bitmapresource.pp --descr=bitmapresource.xml \
+  --input=../src/acceleratorsresource.pp --descr=acceleratorsresource.xml \
+  --input=../src/groupresource.pp --descr=groupresource.xml \
+  --input=../src/groupiconresource.pp --descr=groupiconresource.xml \
+  --input=../src/groupcursorresource.pp --descr=groupcursorresource.xml \
+  --input=../src/stringtableresource.pp --descr=stringtableresource.xml \
+  --input=../src/versionconsts.pp --descr=versionconsts.xml \
+  --input=../src/versiontypes.pp --descr=versiontypes.xml \
+  --input=../src/versionresource.pp --descr=versionresource.xml \
+  --input=../src/cofftypes.pp --descr=cofftypes.xml \
+  --input=../src/coffreader.pp --descr=coffreader.xml \
+  --input=../src/coffwriter.pp --descr=coffwriter.xml \
+  --input=../src/winpeimagereader.pp --descr=winpeimagereader.xml \
+  --input=../src/elfconsts.pp --descr=elfconsts.xml \
+  --input=../src/elfreader.pp --descr=elfreader.xml \
+  --input=../src/elfwriter.pp --descr=elfwriter.xml \
+  --input=../src/machotypes.pp --descr=machotypes.xml \
+  --input=../src/machoreader.pp --descr=machoreader.xml \
+  --input=../src/machowriter.pp --descr=machowriter.xml \
+  --input=../src/externaltypes.pp --descr=externaltypes.xml \
+  --input=../src/externalreader.pp --descr=externalreader.xml \
+  --input=../src/externalwriter.pp --descr=externalwriter.xml \
+  --input=../src/dfmreader.pp --descr=dfmreader.xml
+
+

+ 260 - 0
packages/fcl-res/xml/resdatastream.xml

@@ -0,0 +1,260 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    resdatastream
+  ====================================================================
+-->
+
+<module name="resdatastream">
+<short>Contains stream classes to provide copy-on-write functionality</short>
+<descr>
+<p>This unit contains various streams that are used to provide copy-on-write mechanism for <link id="resource.TAbstractResource.RawData">TAbstractResource.RawData</link>, via more levels of indirection.</p>
+<p>Main class is <link id="TResourceDataStream"/>, which is the stream used for <link id="resource.TAbstractResource.RawData">TAbstractResource.RawData</link>. This class uses an underlying stream, to which it redirects operations.</p>
+<p>At a lower level, a <link id="TCachedDataStream"/> descendant provides a layer between the original stream and the <link id="TResourceDataStream"/>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TCachedDataStream">
+<short>Base cached stream class</short>
+<descr>
+<p>This abstract class provides basic cached stream functionalities.</p>
+<p>A cached stream is a read-only stream that operates on a portion of another stream. That is, it creates a "window" on the original stream from which to read data. Since it is a read-only stream, trying to write to the stream or to set its size cause an EInvalidOperation exception to be raised.</p>
+<p>This class is used by <link id="TResourceDataStream"/> to access the raw data of a resource. When an attempt to write to the stream is detected, <link id="TResourceDataStream"/> replaces it with a memory stream and copies the contents of the cached stream to the memory one, thus providing a copy-on-write mechanism.</p>
+<remark>An object of this class should never be directly instantiated: use a descendant class instead.</remark>
+</descr>
+<seealso>
+<link id="TResourceDataStream"/>
+<link id="TCachedResourceDataStream"/>
+</seealso>
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TCachedDataStream.fStream">
+<short>The original stream</short>
+<descr>
+<p>This protected member is provided to let descendant classes access the original stream.</p>
+</descr>
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TCachedDataStream.fSize">
+<short>The size of the cached stream</short>
+<descr>
+<p>This protected member is provided to let descendant classes access the size of the cached stream.</p>
+</descr>
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TCachedDataStream.fPosition">
+<short>The position from the cached stream perspective</short>
+<descr>
+<p>This protected member is provided to let descendant classes access the position of the cached stream.</p>
+</descr>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TCachedDataStream.Create">
+<short>Creates a new object</short>
+<descr>
+<p>A new cached stream is created on top of the <var>aStream</var> stream.</p>
+</descr>
+<seealso>
+<link id="TCachedDataStream"/>
+<link id="TResourceDataStream"/>
+<link id="TResourceDataStream.Create"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TCachedDataStream.Create.aStream">
+<short>The stream from which to read data</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TCachedDataStream.Create.aResource">
+<short>The resource whose data must be read</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TCachedDataStream.Create.aSize">
+<short>The size of the resource data</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TCachedResourceDataStream">
+<short>An implementation of a cached stream</short>
+<descr>
+<p>This class provides an implementation of <link id="TCachedDataStream"/>.</p>
+<p>Usually resource readers create a <link id="TResourceDataStream"/> with a TCachedResourceDataStream as the underlying stream.</p>
+</descr>
+<seealso>
+<link id="TCachedDataStream"/>
+<link id="TResourceDataStream"/>
+</seealso>
+</element>
+
+<!-- "class of" type Visibility: default -->
+<element name="TCachedStreamClass">
+<short>Cached stream metaclass</short>
+</element>
+
+<!-- enumeration type Visibility: default -->
+<element name="TUnderlyingStreamType">
+<short>The type of the underlying stream of TResourceDataStream</short>
+<seealso>
+<link id="TResourceDataStream"/>
+</seealso>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TUnderlyingStreamType.usCached">
+<short>The underlying stream is a TCachedResourceDataStream descendant</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TUnderlyingStreamType.usMemory">
+<short>The underlying stream is a memory stream</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TUnderlyingStreamType.usCustom">
+<short>The underlying stream is a custom stream</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TResourceDataStream">
+<short>Stream class that provides copy-on-write functionality</short>
+<descr>
+<p>This class provides the copy-on-write mechanism of <link id="resource.TAbstractResource.RawData">TAbstractResource.RawData</link>, via more levels of indirection.</p>
+<p>It uses an underlying stream, to which it redirects operations.</p>
+<p>The underlying stream can be a <link id="TCachedDataStream"/> descendant, a memory stream or a custom stream. Usually when a resource is loaded from a stream, the underlying stream is a <link id="TCachedDataStream"/> descendant, which provides a read-only stream-like interface over a portion of the original stream (that is, the part of the original stream where resource data resides). When <link id="TResourceDataStream"/> is requested to write data, it replaces the underlying stream with a memory stream, whose contents are copied from the previous underlying stream: this way, copy-on-write functionality can be achieved.</p>
+<p>As said before, third possibility is to have a custom stream as the underlying stream: a user can set this stream via <link id="resource.TAbstractResource.SetCustomRawDataStream">TAbstractResource.SetCustomRawDataStream</link> method, which in turn calls <link id="TResourceDataStream.SetCustomStream"/></p>	
+<p><b>Figure</b>: Levels of indirection</p>
+<pre>
+.
+                     TResourceDataStream
+                              |
+       _______________________|_______________________________
+      |                       |                               |
+TMemoryStream     TCachedDataStream descendant          custom stream
+                         /           \
+ _______________________|_____________|______________________________
+|                o r i g|i n a l   s t|r e a m                       |
+|_______________________|_____________|______________________________|
+
+</pre>
+</descr>
+<seealso>
+<link id="TCachedDataStream"/>
+<link id="TResourceDataStream.Create"/>
+<link id="TResourceDataStream.SetCustomStream"/>
+</seealso>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TResourceDataStream.Create">
+<short>Creates a new object</short>
+<descr>
+<p>A new <link id="TResourceDataStream"/> object is created.</p>
+<p>If <var>aStream</var> is <var>nil</var>, the underlying stream is a memory stream. Otherwise, a cached stream of the class specified in <var>aClass</var> is created and set as the underlying stream.</p>
+</descr>
+<seealso>
+<link id="TResourceDataStream"/>
+<link id="TCachedDataStream"/>
+<link id="TResourceDataStream.SetCustomStream"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDataStream.Create.aStream">
+<short>The stream which resource data must be read from. It can be <var>nil</var></short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDataStream.Create.aResource">
+<short>The resource whose data must be read</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDataStream.Create.aSize">
+<short>The size of the resource data</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDataStream.Create.aClass">
+<short>The class to use to create the underlying cached stream</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceDataStream.Compare">
+<short>Compares the stream to another one</short>
+<descr>
+<p>This methods compares the stream with <var>aStream</var>. If they are of the same length and their contents are the same, <var>true</var> is returned, <var>false</var> otherwise.</p>
+</descr>
+<seealso>
+<link id="resource.TAbstractResource.CompareContents">TAbstractResource.CompareContents</link>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceDataStream.Compare.Result">
+<short>True if the contents of the two streams are the same</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDataStream.Compare.aStream">
+<short>The stream to compare to this one. It can be <var>nil</var></short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResourceDataStream.SetCustomStream">
+<short>Sets a custom stream as the underlying stream</short>
+<descr>
+<p>This method sets a custom stream as the underlying stream.</p>
+<p>If <var>aStream</var> is <var>nil</var>, a new memory stream is used as the underlying stream. This can be used to remove a previously set custom stream as the underlying stream.</p>
+<p>Usually it is called by <link id="resource.TAbstractResource.SetCustomRawDataStream">TAbstractResource.SetCustomRawDataStream</link>.</p>
+</descr>
+<seealso>
+<link id="TResourceDataStream"/>
+<link id="resource.TAbstractResource.SetCustomRawDataStream">TAbstractResource.SetCustomRawDataStream</link>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDataStream.SetCustomStream.aStream">
+<short>The stream to use as the underlying stream. It can be <var>nil</var></short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceDataStream.Cached">
+<short>Controls the copy-on-write behaviour of the stream</short>
+<descr>
+<p>When this property is set to <var>true</var>, a cached stream is used as the underlying stream for read operations. If it is set to <var>false</var>, no caching is performed and data is always copied to a memory stream.</p>
+<p>Note that this property does nothing if the underlying stream is a custom stream.</p>
+<p>By default this property is true.</p>
+</descr>
+<seealso>
+<link id="TResourceDataStream"/>
+<link id="resource.TAbstractResource.CacheData">TAbstractResource.CacheData</link>
+</seealso>
+</element>
+
+</module> <!-- resdatastream -->
+
+</package>
+</fpdoc-descriptions>

+ 122 - 0
packages/fcl-res/xml/resfactory.xml

@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    resfactory
+  ====================================================================
+-->
+
+<module name="resfactory">
+<short>Contains a factory class for resources</short>
+<descr>
+<p>This unit contains a factory class that provides an easy way to create resources of the right class.</p>
+<p>Resource classes can be registered with <link id="TResourceFactory"/> so that the class knows how to create a resource of a specific type.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceFactoryException">
+<short>Base class for resource factory-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceClassAlreadyRegisteredException">
+<short>A resource class for a given type has already been registered</short>
+<descr>
+<p>This exception is raised by class method <link id="TResourceFactory.RegisterResourceClass">RegisterResourceClass</link> of <link id="TResourceFactory"/> when an attempt is made to register a class for an already registered type.</p>
+</descr>
+<seealso>
+<link id="TResourceFactory.RegisterResourceClass"/>
+</seealso>
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SAlreadyRegistered">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TResourceFactory">
+<short>Factory class for resources</short>
+<descr>
+<p>Resources are represented by descendants of <link id="resource.TAbstractResource">TAbstractResource</link>. Some applications don't need specialized resource classes, and a <link id="resource.TGenericResource">TGenericResource</link> can be enough. On the other hand, sometimes it is required that a resource of a specific type is created with a more specialized class. This class provides a centralized point for the creation of resources.</p>
+<p><link id="TResourceFactory"/> holds a list of registered classes with an associated resource type. When it is requested to create a resource for a given type, it creates a resource of the class associated with that type. If no class matching that type is found, <link id="resource.TGenericResource">TGenericResource</link> is used.</p>
+<p>Usually each resource class registers itself in the <var>initialization</var> section of the unit in which it is implemented.</p>
+</descr>
+<seealso>
+<link id="TResourceFactory.RegisterResourceClass"/>
+<link id="TResourceFactory.CreateResource"/>
+<link id="resource.TAbstractResource">TAbstractResource</link>
+<link id="resource.TGenericResource">TGenericResource</link>
+</seealso>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResourceFactory.RegisterResourceClass">
+<short>Registers a resource class</short>
+<descr>
+<p>This class method registers a resource class for the given resource type.</p>
+</descr>
+<errors>
+<p>If a class has already been registered for the given resource type, an <link id="EResourceClassAlreadyRegisteredException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TResourceFactory"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceFactory.RegisterResourceClass.aType">
+<short>The type associated to the resource class</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceFactory.RegisterResourceClass.aClass">
+<short>The resource class to register</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceFactory.CreateResource">
+<short>Creates a new resource</short>
+<descr>
+<p>This class method creates a new resource of the class associated with the given type, and sets its name and type based on the values passed as parameters.</p>
+<p>If no class matching the given type is found, the resource is created with <link id="resource.TGenericResource">TGenericResource</link> class.</p>
+</descr>
+<seealso>
+<link id="TResourceFactory"/>
+<link id="TResourceFactory.RegisterResourceClass"/>
+<link id="resource.TGenericResource">TGenericResource</link>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceFactory.CreateResource.Result">
+<short>A new resource</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceFactory.CreateResource.aType">
+<short>The type of the resource to create</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceFactory.CreateResource.aName">
+<short>The name of the resource to create</short>
+</element>
+
+</module> <!-- resfactory -->
+
+</package>
+</fpdoc-descriptions>

+ 2843 - 0
packages/fcl-res/xml/resource.xml

@@ -0,0 +1,2843 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<topic name="Format of resources in object files">
+<short>Format of resources in object files</short>
+<descr>
+<p><b>Introduction</b></p>
+<p>This appendix describes the format in which resources are stored in object files. This doesn't apply to PECOFF file format, where a format already exists and is well described in documentation from Microsoft.</p>
+<p>On Microsoft Windows, resources are natively supported by the operating system. On other systems, Free Pascal RTL provides access to resources, which are embedded in the executable file in the format that is here described.</p>
+<p>This appendix doesn't describe a particular object file format implementation (e.g. ELF or Mach-O), but the layout of the sections involved in supporting resources: the way these sections are actually laid out on a file are subject to the rules of the hosting object file format.</p>
+<p>For external resource file details, see <link id ="externaltypes.Description of external resource file format">Description of external resource file format</link></p>
+<p><b>Conventions</b></p>
+<p>In this document, data sizes are specified with pascal-style data types. They are the following:</p>
+<table>
+<th><td>Name</td><td>Meaning</td></th>
+<tr><td><var>longword</var></td><td>Unsigned 32 bit integer.</td></tr>
+<tr><td><var>ptruint</var></td><td>Unsigned integer of the size of a pointer</td></tr>
+</table>
+<p>Byte order is the one of the target machine.</p>
+<p>All data structures in the sections must be aligned on machine boundaries (4 bytes for 32 bit machines, 8 bytes for 64 bit machines).</p>
+<p>Note that all pointers must be valid at runtime. This means that relocations must be written to the object file so that the linker can relocate pointers to the addresses they will have at runtime. Note also that pointers to strings are really pointers, and not offsets to the beginning of the string table.</p>
+<p><b>Resource sections</b></p>
+<p>Free Pascal uses two sections to store resource information:</p>
+<ul>
+<li><var>fpc.resources</var>. This is a data section that contains all required structures. It must be writable.</li>
+<li><var>fpc.rehandles</var>. This is a bss section whose size must be equal to <var>(total number of resources)*(size of pointer)</var>. It must be writable.</li>
+</ul>
+<p>The rest of this chapter will describe the contents of <var>fpc.resources</var> section.</p>
+<p><b>Resource section layout</b></p>
+<p>The <var>fpc.resources</var> section consists of these parts:</p>
+<ul>
+<li>The initial header</li>
+<li>The resource tree, in the form of nodes</li>
+<li>The string table, which can be optional</li>
+<li>The resource data</li>
+</ul>
+<p><b>The initial header</b></p>
+<p>The <var>fpc.resources</var> section starts with this header:</p>
+<table>
+	<th><td>Name</td><td>Offset</td><td>Length</td><td>Description</td></th>
+	<tr>
+		<td>rootptr</td>
+		<td>0</td>
+		<td>ptruint</td>
+		<td>Pointer to the root node.</td>
+	</tr>
+	<tr>
+		<td>count</td>
+		<td>4/8</td>
+		<td>longword</td>
+		<td>Total number of resources.</td>
+	</tr>
+	<tr>
+		<td>usedhandles</td>
+		<td>8/12</td>
+		<td>longword</td>
+		<td>Used at runtime. Set to zero in object files.</td>
+	</tr>
+	<tr>
+		<td>handles</td>
+		<td>12/16</td>
+		<td>ptruint</td>
+		<td>Pointer to the first byte of <var>fpc.reshandles</var> section.</td>
+	</tr>
+</table>
+<p><b>The resource tree</b></p>
+<p>Immediately following the initial header, the resource tree comes. It is made up by nodes that represent resource types, names and language ids.</p>
+<p>Data is organized so that resource information (type, name and language id) is represented by a tree: root node contains resource types, that in turn contain resource names, which contain language ids, which describe resource data.</p>
+<p>Given a node, its sub-nodes are ordered as follows:</p>
+<ul>
+<li>First the "named" nodes (nodes that use a string as identifier) come, then the id ones (nodes that use an integer as identifier).</li>
+<li>Named nodes are alphabetically sorted, in ascending order.</li>
+<li>Id nodes are sorted in ascending order.</li>
+</ul>
+<p>In the file, all sub-nodes of a node are written in the order described above. Then, all sub-nodes of the first sub-node are written, and so on.</p>
+<p><b>Example:</b></p>
+<p>There are three resources:</p>
+<ol>
+<li>a <var>BITMAP</var> resource with name <var>MYBITMAP</var> and language id <var>$0409</var></li>
+<li>a <var>BITMAP</var> resource with name <var>1</var> and language id <var>0</var></li>
+<li>a resource with type <var>MYTYPE</var> and name <var>1</var> and language id <var>0</var></li>
+</ol>
+<p>Nodes are laid out this way (note that <var>BITMAP</var> resources have type <var>2</var>):</p>
+<pre>
+	
+	root | MYTYPE 2 | 1 | 0 | MYBITMAP 1 | $0409 | 0
+</pre>
+<p>That is, types (<var>MYTYPE</var> is a string, so it comes before <var>2</var> which is <var>BITMAP</var>), then names for <var>MYTYPE</var> (<var>1</var>), then language id for resource 3 (<var>0</var>), then names for <var>BITMAP</var> (<var>MYBITMAP</var> and <var>1</var>), then language id for resource 1 (<var>$0409</var>), then language id for resource 2 (<var>0</var>).</p>
+<p><b>Node format</b></p>
+<table>
+	<th><td>Name</td><td>Offset</td><td>Length</td><td>Description</td></th>
+	<tr>
+		<td>nameid</td>
+		<td>0</td>
+		<td>ptruint</td>
+		<td>name pointer, integer id or language id</td>
+	</tr>
+	<tr>
+		<td>ncount</td>
+		<td>4/8</td>
+		<td>longword</td>
+		<td>named sub-nodes count</td>
+	</tr>
+	<tr>
+		<td>idcountsize</td>
+		<td>8/12</td>
+		<td>longword</td>
+		<td>id sub-nodes count or resource size</td>
+	</tr>
+	<tr>
+		<td>subptr</td>
+		<td>12/16</td>
+		<td>ptruint</td>
+		<td>pointer to first sub-node</td>
+	</tr>
+</table>
+<p>If the node is identified by a string, <var>nameid</var> is a pointer to the null-terminated string holding the name. If it is identified by an id, <var>nameid</var> is that id. Language id nodes are always identified by and ID.</p>
+<p><var>ncount</var> is the number of named sub-nodes of this node (nodes that are identified by a string).</p>
+<p><var>idcountsize</var> is the number of id sub-nodes of this node (nodes that are identified by an integer id). For language id nodes, this field holds the size of the resource data.</p>
+<p><var>subptr</var> is an pointer to the first subnode of this node. Note that it allows to access every subnode of this node, since subnodes of a node always come one after the other. For language id nodes, <var>subptr</var> is the pointer to the resource data.</p>
+<p><b>The string table</b></p>
+<p>The string table is used to store strings used for resource types and names. If all resources use integer ids for name and types, it may not be present in the file.</p>
+<p>The string table simply contains null-terminated strings, one after the other.</p>
+<p>If present, the string table always contains a <var>0</var> (zero) at the beginning. This way, the empty string is located at the first byte of the string table.</p>
+<p><b>The resource data</b></p>
+<p>This part of the file contains raw resource data. As written before, all data structures must be aligned on machine boundaries, so if a resource data size is not a multiple of 4 (for 32 bit machines) or 8 (for 64 bit machines), bytes of padding must be inserted after that resource data.</p>
+<p><b>Exported symbols</b></p>
+<p>Object files containing resources must export a pointer to the first byte of <var>fpc.resources</var> section. The name of this symbol is <var>FPC_RESSYMBOL</var>.</p>
+<p><b>Mach-O specific notes</b></p>
+<p><var>fpc.resources</var> and <var>fpc.reshandles</var> sections are to be contained in a <var>__DATA</var> segment.</p>
+</descr>
+</topic>
+
+<topic name="How to implement a new resource writer">
+<short>How to implement a new resource writer</short>
+<descr>
+<remark>This chapter assumes you have some experience in using this library.</remark>
+<p>We'll see how to implement a writer for a new resource file format. A resource writer is a descendant of <link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link>, and it's usually implemented in a unit named <var>namewriter</var>, where <i>name</i> is file format name.</p>
+<p>Suppose we must write a writer for file format <i>foo</i>; we could start with a unit like this:</p>
+<code>
+unit foowriter;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+
+type
+  TFooResourceWriter = class (TAbstractResourceWriter)
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Write(aResources : TResources; aStream : TStream); override;
+  public
+    constructor Create; override;
+  end;
+
+implementation
+
+function TFooResourceWriter.GetExtensions: string;
+begin
+
+end;
+
+function TFooResourceWriter.GetDescription: string;
+begin
+
+end;
+
+procedure TFooResourceWriter.Write(aResources: TResources; aStream: TStream);
+begin
+
+end;
+
+constructor TFooResourceWriter.Create;
+begin
+
+end;
+
+initialization
+  TResources.RegisterWriter('.foo',TFooResourceWriter);
+
+end.
+</code>
+<p>Note that in the <var>initialization</var> section, <var>TFooResourceWriter</var> is registered for extension <var>.foo</var>.</p>
+<p>We must implement abstract methods of <link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link>. Let's start with the simpler ones, <link id="resource.TAbstractResourceWriter.GetExtensions">GetExtensions</link> and <link id="resource.TAbstractResourceWriter.GetDescription">GetDescription</link>.</p>
+<code>
+function TFooResourceWriter.GetExtensions: string;
+begin
+  Result:='.foo';
+end;
+
+function TFooResourceWriter.GetDescription: string;
+begin
+  Result:='FOO resource writer';
+end;
+</code>
+<p>Now let's see <link id="resource.TAbstractResourceWriter.Write">Write</link>. This method must write all resources in the <link id="resource.TResources">TResources</link> object to the stream.</p>
+<p>Suppose that our foo format is very simple:</p>
+<ul>
+<li>the header is made by a 4-byte signature (<var>FOO*</var>), a <var>longword</var> holding the number of resources in the file, and other 8 bytes of padding.</li>
+<li><p>each resource has a 16-byte header containing:</p>
+<ul>
+<li>a longword for the resource type (only IDs are allowed for types)</li>
+<li>a longword for the resource name (only IDs are allowed for names)</li>
+<li>a longword for the language ID</li>
+<li>a longword for the size of the resource data</li>
+</ul>
+</li>
+<li>
+after the resource header immediately comes the resource data, possibly padded so that it ends on a 4 byte boundary.
+</li>
+<li>
+file format is little-endian
+</li>
+</ul>
+<p>Our <link id="resource.TAbstractResourceWriter.Write">Write</link> method could be something like this:</p>
+<code>
+procedure TFooResourceWriter.Write(aResources: TResources; aStream: TStream);
+var i : integer;
+begin
+  WriteFileHeader(aStream,aResources);
+  for i:=0 to aResources.Count-1 do
+    WriteResource(aStream,aResources[i]);
+end;
+</code>
+<p>So we must implement <var>WriteFileHeader</var>, which writes the 16-byte file header, and <var>WriteResource</var>, which writes a single resource with its header.</p>
+<p>Let's start from the first one:</p>
+<code>
+procedure TFooResourceWriter.WriteFileHeader(aStream: TStream; aResources: TResources);
+var signature : array[0..3] of char;
+    rescount : longword;
+    padding : qword;
+begin
+  signature:='FOO*';
+  rescount:=aResources.Count;
+  padding:=0;
+
+  aStream.WriteBuffer(signature[0],4);
+  aStream.WriteBuffer(rescount,sizeof(rescount));
+  aStream.WriteBuffer(padding,sizeof(padding));
+end;
+</code>
+<p>This code simply writes the file header as defined in foo format. Note that if we are running on a big endian system we should swap bytes before writing, e.g. calling <var>SwapEndian</var> function, but for simplicity this is omitted.</p>
+<p>Now <var>WriteResource</var> comes. This method could be like this:</p>
+<code>
+procedure TFooResourceWriter.WriteResource(aStream: TStream; aResource: TAbstractResource);
+var aType : longword;
+    aName : longword;
+    aLangID : longword;
+    aDataSize : longword;
+begin
+  aType:=aResource._Type.ID;
+  aName:=aResource.Name.ID;
+  aLangID:=aResource.LangID;
+  aDataSize:=aResource.RawData.Size;
+
+  //write resource header
+  aStream.WriteBuffer(aType,sizeof(aType));
+  aStream.WriteBuffer(aName,sizeof(aName));
+  aStream.WriteBuffer(aLangID,sizeof(aLangID));
+  aStream.WriteBuffer(aDataSize,sizeof(aDataSize));
+
+  //write resource data
+  aResource.RawData.Position:=0;
+  aStream.CopyFrom(aResource.RawData,aResource.RawData.Size);
+
+  //align data so that it ends on a 4-byte boundary
+  Align4Bytes(aStream);
+end;
+</code>
+<p>We write the 16-byte resource header, and then resource data. Note that if resources have been loaded from a stream and the user didn't modify resource data, we are copying data directly from the original stream.</p>
+<p><var>Align4Bytes</var> is a private method (not shown for simplicity) that writes some padding bytes to the stream if needed, since FOO file format specifies that resource data must be padded to end on a 4 byte boundary. Again, we didn't consider endianess for simplicity. And finally, note that foo format only supports IDs for types and names, so if one of them is a name (that is, a string) this code might cause exceptions to be raised.</p>
+<p><b>Note:</b> More complex file formats store resources in a tree hierarchy; since <link id="resource.TResources">TResources</link> internally stores resources in this way too, a writer can choose to acquire a reference to the internal tree used by the <link id="resource.TResources">TResources</link> object (see <link id="resource.TAbstractResourceWriter.GetTree">TAbstractResourceWriter.GetTree</link>) and use it directly. For these file formats resources can be written faster, since there is no overhead involved in building a separate resource tree in the writer.</p>
+<p>That's all. Now you should be able to create a real resource writer.</p>
+</descr>
+</topic>
+
+<topic name="How to implement a new resource reader">
+<short>How to implement a new resource reader</short>
+<descr>
+<remark>This chapter assumes you have some experience in using this library.</remark>
+<p>We'll see how to implement a reader for a new resource file format. A resource reader is a descendant of <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link>, and it's usually implemented in a unit named <var>namereader</var>, where <i>name</i> is file format name.</p>
+<p>Suppose we must write a reader for file format <i>foo</i>; we could start with a unit like this:</p>
+<code>
+unit fooreader;
+
+{$MODE OBJFPC} {$H+}
+
+interface
+
+uses
+  Classes, SysUtils, resource;
+
+type
+  TFooResourceReader = class(TAbstractResourceReader)
+  protected
+    function GetExtensions : string; override;
+    function GetDescription : string; override;
+    procedure Load(aResources : TResources; aStream : TStream); override;
+    function CheckMagic(aStream : TStream) : boolean; override;
+  public
+    constructor Create; override;
+  end;
+
+implementation
+
+function TFooResourceReader.GetExtensions: string;
+begin
+
+end;
+
+function TFooResourceReader.GetDescription: string;
+begin
+
+end;
+
+procedure TFooResourceReader.Load(aResources: TResources; aStream: TStream);
+begin
+
+end;
+
+function TFooResourceReader.CheckMagic(aStream: TStream): boolean;
+begin
+
+end;
+
+constructor TFooResourceReader.Create;
+begin
+
+end;
+
+initialization
+  TResources.RegisterReader('.foo',TFooResourceReader);
+
+end.
+</code>
+<p>Note that in the <var>initialization</var> section, <var>TFooResourceReader</var> is registered for extension <var>.foo</var>.</p>
+<p>We must implement abstract methods of <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link>. Let's start with the simpler ones, <link id="resource.TAbstractResourceReader.GetExtensions">GetExtensions</link> and <link id="resource.TAbstractResourceReader.GetDescription">GetDescription</link>.</p>
+<code>
+function TFooResourceReader.GetExtensions: string;
+begin
+  Result:='.foo';
+end;
+
+function TFooResourceReader.GetDescription: string;
+begin
+  Result:='FOO resource reader';
+end;
+</code>
+<p>Now let's see <link id="resource.TAbstractResourceReader.CheckMagic">CheckMagic</link> method. This method is called with a stream as a parameter, and the reader must return <var>true</var> if it recognizes the stream as a valid one. Usually this means checking some magic number or header.</p>
+<code>
+function TFooResourceReader.CheckMagic(aStream: TStream): boolean;
+var signature : array[0..3] of char;
+begin
+  Result:=false;
+  try
+    aStream.ReadBuffer(signature[0],4);
+  except
+    on e : EReadError do exit;
+  end;
+  Result:=signature='FOO*';
+end; 
+</code>
+<p>Suppose our foo files start with a 4-byte signature <var>'FOO*'</var>. This method checks the signature and returns <var>true</var> if it is verified. Note that it catches <var>EReadError</var> exception raised by <var>TStream</var>: this way, if the stream is too short it returns <var>false</var> (as it should, since magic is not valid) instead of letting the exception to propagate.</p>
+<p>Now let's see <link id="resource.TAbstractResourceReader.Load">Load</link>. This method must read the stream and create resources in the <link id="resource.TResources">TResources</link> object, with information about their name, type, position and size of their raw data, and so on.</p>
+<code>
+procedure TFooResourceReader.Load(aResources: TResources; aStream: TStream);
+begin
+  if not CheckMagic(aStream) then
+    raise EResourceReaderWrongFormatException.Create('');
+  try
+    ReadResources(aResources,aStream);
+  except
+    on e : EReadError do
+      raise EResourceReaderUnexpectedEndOfStreamException.Create('');
+  end;
+end;
+</code>
+<p>First of all, this method checks file magic number, calling <link id="resource.TAbstractResourceReader.CheckMagic">CheckMagic</link> method we already implemented. This is necessary since <link id="resource.TAbstractResourceReader.CheckMagic">CheckMagic</link> is not called before <link id="resource.TAbstractResourceReader.Load">Load</link>: <link id="resource.TAbstractResourceReader.CheckMagic">CheckMagic</link> is invoked by <link id="resource.TResources">TResources</link> when probing a stream, while <link id="resource.TAbstractResourceReader.Load">Load</link> is invoked when loading resources (so if the user passed a reader object to a <link id="resource.TResources">TResources</link> object, <link id="resource.TAbstractResourceReader.CheckMagic">CheckMagic</link> is never called). Note also that the stream is always at its starting position when these methods are called.</p>
+<p>If magic number is ok, our method invokes another method to do the actual loading. If during this process the stream can't be read, an <link id="resource.EResourceReaderUnexpectedEndOfStreamException">EResourceReaderUnexpectedEndOfStreamException</link> exception is raised.</p>
+<p>So, let's implement the private method which will load resources.</p>
+<p>Suppose that our foo format is very simple:</p>
+<ul>
+<li>the header is made by the 4-byte signature we already saw, a <var>longword</var> holding the number of resources in the file, and other 8 bytes of padding.</li>
+<li><p>each resource has a 16-byte header containing:</p>
+<ul>
+<li>a longword for the resource type (only IDs are allowed for types)</li>
+<li>a longword for the resource name (only IDs are allowed for names)</li>
+<li>a longword for the language ID</li>
+<li>a longword for the size of the resource data</li>
+</ul>
+</li>
+<li>
+after the resource header immediately comes the resource data, possibly padded so that it ends on a 4 byte boundary.
+</li>
+<li>
+file format is little-endian
+</li>
+</ul>
+<p>To start with, our method will be:</p>
+<code>
+procedure TFooResourceReader.ReadResources(aResources: TResources; aStream: TStream);
+var Count, i: longword;
+    aType, aName, aLangID : longword;
+    aDataSize : longword;
+begin
+  //read remaining file header
+  aStream.ReadBuffer(Count,sizeof(Count));
+  aStream.Seek(8,soFromCurrent);
+
+  for i:=1 to Count do
+  begin
+    //read resource header
+    aStream.ReadBuffer(aType,sizeof(aType));
+    aStream.ReadBuffer(aName,sizeof(aName));
+    aStream.ReadBuffer(aLangID,sizeof(aLangID));
+    aStream.ReadBuffer(aDataSize,sizeof(aDataSize));
+
+  end;
+end;
+</code>
+<p>Since in <link id="resource.TAbstractResourceReader.Load">Load</link> we called <link id="resource.TAbstractResourceReader.CheckMagic">CheckMagic</link>, which read the first 4 bytes of the header, we must read the remaining 12: we read the number of resources, and we skip the other 8 bytes of padding.</p>
+<p>Then, for each resource, we read the resource header. Note that if we are running on a big endian system we should swap the bytes we read, e.g. calling <var>SwapEndian</var> function, but for simplicity this is omitted.</p>
+<p>Now, we should create a resource. Of which class? Well, we must use <link id="resfactory"/> unit. In fact it contains <link id="resfactory.TResourceFactory">TResourceFactory</link> class, which is an expert in creating resources of the right class: when the user adds a unit containing a resource class to the <var>uses</var> clause of its program, the resource class registers itself with <link id="resfactory.TResourceFactory">TResourceFactory</link>. This way it knows how to map resource types to resource classes.</p>
+<p>We need to have type and name of the resource to create as <link id="resource.TResourceDesc">TResourceDesc</link> objects: instead of creating and destroying these objects for each resource, we'll create a couple in the creator of our reader and we'll destroy them in the destructor, so that they will live for the whole life of our reader. Let's name them <var>workType</var> and <var>workName</var>.</p>
+<p>Our code becomes:</p>
+<code>
+uses
+  resfactory;
+
+procedure TFooResourceReader.ReadResources(aResources: TResources; aStream: TStream);
+var Count, i: longword;
+    aType, aName, aLangID : longword;
+    aDataSize : longword;
+    aRes : TAbstractResource;
+begin
+  //read remaining file header
+  aStream.ReadBuffer(Count,sizeof(Count));
+  aStream.Seek(8,soFromCurrent);
+
+  for i:=1 to Count do
+  begin
+    //read resource header
+    aStream.ReadBuffer(aType,sizeof(aType));
+    aStream.ReadBuffer(aName,sizeof(aName));
+    aStream.ReadBuffer(aLangID,sizeof(aLangID));
+    aStream.ReadBuffer(aDataSize,sizeof(aDataSize));
+
+    //create the resource
+    workType.ID:=aType;
+    workName.ID:=aName;
+    aRes:=TResourceFactory.CreateResource(workType,workName);
+    SetDataSize(aRes,aDataSize);
+    SetDataOffset(aRes,aStream.Position);
+    aRes.LangID:=aLangID;
+
+  end;
+end;
+</code>
+<p>Note that after the resource has been created we set its data size and data offset. Data offset is the current position in the stream, since in our FOO file format resource data immediately follows resource header.</p>
+<p>What else do we need to do? Of course we must create <link id="resource.TAbstractResource.RawData">RawData</link> stream for our resource, so that raw data can be accessed with the caching mechanism. We will create a <link id="resdatastream.TResourceDataStream">TResourceDataStream</link> object, telling it which resource and stream it is associated to, which its size will be and which class its underlying cached stream must be created from.</p>
+<p>So we add <link id="resdatastream"/> to the <var>uses</var> clause, declare another local variable</p>
+<code>
+aRawData : TResourceDataStream;
+</code>
+<p>and add these lines in the for loop</p>
+<code>
+aRawData:=TResourceDataStream.Create(aStream,aRes,aRes.DataSize,TCachedResourceDataStream);
+SetRawData(aRes,aRawData);
+</code>
+<p>That is, aRawData will create its underlying stream as a <link id="resdatastream.TCachedResourceDataStream">TCachedResourceDataStream</link> over the portion of <var>aStream</var> that starts at current position and ends after <var>aRes.DataSize bytes</var>.</p>
+<p>We almost finished: now we must add the newly created resource to the <link id="resource.TResources">TResources</link> object and move stream position to the next resource header. Complete code for <var>ReadResources</var> method is:</p>
+<code>
+procedure TFooResourceReader.ReadResources(aResources: TResources; aStream: TStream);
+var Count, i: longword;
+    aType, aName, aLangID : longword;
+    aDataSize : longword;
+    aRes : TAbstractResource;
+    aRawData : TResourceDataStream;
+begin
+  //read remaining file header
+  aStream.ReadBuffer(Count,sizeof(Count));
+  aStream.Seek(8,soFromCurrent);
+
+  for i:=1 to Count do
+  begin
+    //read resource header
+    aStream.ReadBuffer(aType,sizeof(aType));
+    aStream.ReadBuffer(aName,sizeof(aName));
+    aStream.ReadBuffer(aLangID,sizeof(aLangID));
+    aStream.ReadBuffer(aDataSize,sizeof(aDataSize));
+
+    //create the resource
+    workType.ID:=aType;
+    workName.ID:=aName;
+    aRes:=TResourceFactory.CreateResource(workType,workName);
+    SetDataSize(aRes,aDataSize);
+    SetDataOffset(aRes,aStream.Position);
+    aRes.LangID:=aLangID;
+
+    //set raw data
+    aRawData:=TResourceDataStream.Create(aStream,aRes,aRes.DataSize,TCachedResourceDataStream);
+    SetRawData(aRes,aRawData);
+
+    //add to aResources
+    try
+      aResources.Add(aRes);
+    except
+      on e : EResourceDuplicateException do
+      begin
+        aRes.Free;
+        raise;
+      end;
+    end;
+
+    //go to next resource header
+    aStream.Seek(aDataSize,soFromCurrent);
+    Align4Bytes(aStream);
+  end;
+end;
+</code>
+<p><var>Align4Bytes</var> is a private method (not shown for simplicity) that sets stream position to the next multiple of 4 if needed, since FOO file format specifies that resource data must be padded to end on a 4 byte boundary.</p>
+<p><b>Note:</b> We have used <link id="resource.TResources.Add">Add</link> method to populate the <link id="resource.TResources">TResources</link> object. More complex file formats store resources in a tree hierarchy; since <link id="resource.TResources">TResources</link> internally stores resources in this way too, a reader can choose to acquire a reference to the internal tree used by the <link id="resource.TResources">TResources</link> object (see <link id="resource.TAbstractResourceReader.GetTree">TAbstractResourceReader.GetTree</link>), populate it and notify the <link id="resource.TResources">TResources</link> object about the added resources (see <link id="resource.TAbstractResourceReader.AddNoTree">TAbstractResourceReader.AddNoTree</link>). For these file formats resources can be loaded faster, since there is no overhead involved in keeping a separate resource tree in the reader.</p>
+<p>That's all. Now you should be able to create a real resource reader.</p>
+</descr>
+</topic>
+
+<topic name="How to implement a new resource class">
+<short>How to implement a new resource class</short>
+<descr>
+<remark>This chapter assumes you have some experience in using this library.</remark>
+<p><b>Some considerations</b></p>
+<p>Usually, a specific resource class is needed when resource data is encoded in a specific binary format that makes working with <link id="resource.TAbstractResource.RawData">RawData</link> uncomfortable.</p>
+<p>However, there aren't many reasons to design a new binary format requiring a specific resource class: the classes provided with this package exist for compatibility with Microsoft Windows, but in the general case one should avoid such approach.</p>
+<p>In Microsoft Windows, some resource types have a specific format, and the operating system supports them at runtime making it easy to access that kind of data: e.g. icons and bitmaps are stored in resources in a format that is slightly different from the one found in regular files, but the operating system allows the user to easily load them using <var>LoadImage</var> function, without having to deal with their internal format. Other resource types are used to obtain information about the executable: <link id="resource.RT_VERSION">RT_VERSION</link> resource type and <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> contain version information and program icon that can be displayed in Windows Explorer, respectively.</p>
+<p>Using this kind of resources in a cross-platform perspective doesn't make much sense however, since there is no support by other operating systems for these types of resources (and for resources in general), and this means that it's up to you to provide support at runtime for these binary formats. So if you need to store images as resources it's better to use <link id="resource.TGenericResource">TGenericResource</link> and store an image in PNG format (for instance), which can be read by existing libraries at runtime, instead of creating a <link id="resource.RT_BITMAP">RT_BITMAP</link> resource with <link id="bitmapresource.TBitmapResource">TBitmapResource</link>, since libraries that read BMP files can't handle that resource contents.</p>
+<p>New resource classes thus make sense when you want to add support for existing Windows-specific resources, e.g. because you are writing a resource compiler or editor, but in the general case they should be avoided.</p>
+<p>Now that you've been warned, let's start with the topic of this chapter.</p>
+<p><b>How to implement a new resource class</b></p>
+<p>A resource class is a descendant of <link id="resource.TAbstractResource">TAbstractResource</link>, and it's usually implemented in a unit named <var>typeresource</var>, where <i>type</i> is resource type.</p>
+<p>If you are implementing a new resource class, you are doing it to provide additional methods or properties to utilize resource data. You resource class must thus be able to read its <link id="resource.TAbstractResource.RawData">RawData</link> stream format and write data back to it when it is requested to do so.</p>
+<p>Generally, your class shouldn't create private objects, records or memory buffers to provide these specific means of accessing data until it's requested to do so (lazy loading), and it should free these things when it is requested to write back data to the <link id="resource.TAbstractResource.RawData">RawData</link> stream.</p>
+<p>We'll see these points in more detail, using <link id="acceleratorsresource.TAcceleratorsResource">TAcceleratorsResource</link> as an example.</p>
+<p><link id="acceleratorsresource.TAcceleratorsResource">TAcceleratorsResource</link> holds a collection of accelerators. An accelerator is a record defined as follows:</p>
+<code>
+type
+  TAccelerator = packed record
+    Flags : word;
+    Ansi : word;
+    Id : word;
+    padding : word;
+  end;
+</code>
+<p>The resource simply contains accelerators, one immediately following the other. Last accelerator must have $80 in its flags.</p>
+<p>To provide easy access to the elements it contains, our accelerator resource class exposes these methods and properties in its public section:</p>
+<code>
+procedure Add(aItem : TAccelerator);
+procedure Clear;
+procedure Delete(aIndex : integer);
+property Count : integer read GetCount;
+property Items[index : integer] : TAccelerator read GetItem write SetItem; default;
+</code>
+<p>We must also implement abstract methods (and an abstract constructor) of <link id="resource.TAbstractResource">TAbstractResource</link>:</p>
+<code>
+protected
+  function GetType : TResourceDesc; override;
+  function GetName : TResourceDesc; override;
+  function ChangeDescTypeAllowed(aDesc : TResourceDesc) : boolean; override;
+  function ChangeDescValueAllowed(aDesc : TResourceDesc) : boolean; override;
+  procedure NotifyResourcesLoaded; override;
+public
+  constructor Create(aType,aName : TResourceDesc); override;
+  procedure UpdateRawData; override;
+</code>
+<p>The protected methods are very easy to implement, so let's start from them. For <link id="resource.TAbstractResource.GetType">GetType</link> and <link id="resource.TAbstractResource.GetName">GetName</link>, we need to add two private fields, <var>fType</var> and <var>fName</var>, of type <link id="resource.TResourceDesc">TResourceDesc</link>. We create them in the constructor and destroy them in the destructor. Type will always be <link id="resource.RT_ACCELERATOR">RT_ACCELERATOR</link>. We make the parameterless constructor of <link id="resource.TAbstractResource">TAbstractResource</link> public, using <var>1</var> as the resource name, while in the other constructor we use the name passed as parameter, ignoring the type (since it must always be <link id="resource.RT_ACCELERATOR">RT_ACCELERATOR</link>).</p>
+<p>So, <link id="resource.TAbstractResource.GetType">GetType</link>, <link id="resource.TAbstractResource.GetName">GetName</link>, the constructors and the destructor are implemented as follows:</p>
+<code>
+function TAcceleratorsResource.GetType: TResourceDesc;
+begin
+  Result:=fType;
+end;
+
+function TAcceleratorsResource.GetName: TResourceDesc;
+begin
+  Result:=fName;
+end;
+
+constructor TAcceleratorsResource.Create;
+begin
+  inherited Create;
+  fType:=TResourceDesc.Create(RT_ACCELERATOR);
+  fName:=TResourceDesc.Create(1);
+  SetDescOwner(fType);
+  SetDescOwner(fName);
+end;
+
+constructor TAcceleratorsResource.Create(aType, aName: TResourceDesc);
+begin
+  Create;
+  fName.Assign(aName);
+end;
+
+destructor TAcceleratorsResource.Destroy;
+begin
+  fType.Free;
+  fName.Free;
+  inherited Destroy;
+end;
+</code>
+<p>Note that we used <link id="resource.TAbstractResource.SetDescOwner">SetDescOwner</link> to let type and name know the resource that owns them.</p>
+<p>Now <link id="resource.TAbstractResource.ChangeDescTypeAllowed">ChangeDescTypeAllowed</link> and <link id="resource.TAbstractResource.ChangeDescValueAllowed">ChangeDescValueAllowed</link> come. As we said, resource type must be <link id="resource.RT_ACCELERATOR">RT_ACCELERATOR</link>, always. Thus, we only allow name to change value or type:</p>
+<code>
+function TAcceleratorsResource.ChangeDescTypeAllowed(aDesc: TResourceDesc): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+
+function TAcceleratorsResource.ChangeDescValueAllowed(aDesc: TResourceDesc): boolean;
+begin
+  Result:=aDesc=fName;
+end;
+</code>
+<p><link id="resource.TAbstractResource.NotifyResourcesLoaded">NotifyResourcesLoaded</link> is called by <link id="resource.TResources">TResources</link> when it finishes loading all resources. Since we are not interested in this fact, we simply leave this method empty. This method is useful for resources that "own" other resources, like <link id="groupiconresource.TGroupIconResource">TGroupIconResource</link> and <link id="groupiconresource.TGroupCursorResource">TGroupCursorResource</link> (note: you should <b>not</b> implement resource types that depend on other resources: it complicates things a lot and gives you a lot of headaches).</p>
+<p>Now, let's see the more interesting - and more difficult - part: providing an easy way to deal with accelerators.</p>
+<p>As we said earlier, we must implement some methods and properties to do so. Surely we'll need a list to hold pointers to accelerator records, but we must think a little bit about how this list is created, populated, written to <link id="resource.TAbstractResource.RawData">RawData</link> and so on.</p>
+<p>When the object is created, we don't have to create (yet) single accelerator records, as said before; but if the user tries to access them we must do it. If the object is created and its <link id="resource.TAbstractResource.RawData">RawData</link> contains data (e.g. because a reader has created the resource when loading a resource file) and the user tries to access an accelerator, we must create accelerators from <link id="resource.TAbstractResource.RawData">RawData</link> contents. So, until a user tries to access accelerators our class doesn't do anything, while when the user does so it "lazy-loads" data, or creates empty structures if <link id="resource.TAbstractResource.RawData">RawData</link> is empty.</p>
+<p>When data is loaded, <link id="resource.TAbstractResource.RawData">RawData</link> contents aren't considered anymore. When, however, our resource is requested to update <link id="resource.TAbstractResource.RawData">RawData</link> (that is, when <link id="resource.TAbstractResource.UpdateRawData">UpdateRawData</link> method is invoked), our "lazy-loaded" data must be freed. In fact, a user could ask our resource to update raw data, then he/she could modify it directly and then could use our resource's specialized methods and properties to do further processing: for this reason, when <link id="resource.TAbstractResource.RawData">RawData</link> is written, other buffered things must be freed, so that they'll created again from <link id="resource.TAbstractResource.RawData">RawData</link> if needed.</p>
+<p>Note that other resource classes could behave differently: e.g. <link id="bitmapresource.TBitmapResource">TBitmapResource</link> uses a copy-on-write mechanism on top of <link id="resource.TAbstractResource.RawData">RawData</link> to insert a BMP file header at the beginning of the stream, but it doesn't copy <link id="resource.TAbstractResource.RawData">RawData</link> contents whenever possible.</p>
+<p>Coming back to our <link id="acceleratorsresource.TAcceleratorsResource">TAcceleratorsResource</link> example, let's see how to implement this behaviour.</p>
+<p>Let's add a <var>fList</var> field in the <var>private</var> section of our class:</p>
+<code>
+fList : TFPList;
+</code>
+<p>In the constructor, we set this field to <var>nil</var>: we use it to check if data has been loaded from <link id="resource.TAbstractResource.RawData">RawData</link> or not. Consequently in the destructor we'll free the list only if it's not <var>nil</var>:</p>
+<code>
+destructor TAcceleratorsResource.Destroy;
+begin
+  fType.Free;
+  fName.Free;
+  if fList&lt;&gt;nil then
+  begin
+    Clear;
+    fList.Free;
+  end;
+  inherited Destroy;
+end;
+</code>
+<p>(we did not implement <var>Clear</var> method yet: we'll see it later).</p>
+<p>We said that our resource must load data only when needed; to do this we add a private method, <var>CheckDataLoaded</var> that ensures that data is loaded. This method is called by whatever method needs to operate on the list: if data has already been loaded it will quickly return, otherwise it will load data.</p>
+<code>
+procedure TAcceleratorsResource.CheckDataLoaded;
+var acc : TAccelerator;
+    tot, i : integer;
+    p : PAccelerator;
+begin
+  if fList&lt;&gt;nil then exit;
+  fList:=TFPList.Create;
+  if RawData.Size=0 then exit;
+  RawData.Position:=0;
+  tot:=RawData.Size div 8;
+  for i:=1 to tot do
+  begin
+    RawData.ReadBuffer(acc,sizeof(acc));
+    GetMem(p,sizeof(TAccelerator));
+    p^:=acc;
+    fList.Add(p);
+  end;
+end;	
+</code>
+<p>If <var>fList</var> is not <var>nil</var> data is already loaded, so exit. Otherwise, create the list. If <link id="resource.TAbstractResource.RawData">RawData</link> is empty we don't need to load anything, so exit. Otherwise allocate room for accelerators, read them from the stream, and add them to the list.</p>
+<p>Note that if we are running on a big endian system we should swap the bytes we read, e.g. calling <var>SwapEndian</var> function, but for simplicity this is omitted.</p>
+<p>The counterpart of <var>CheckDataLoaded</var> is <link id="resource.TAbstractResource.UpdateRawData">UpdateRawData</link>. When it is called, data from the list must be written back to <link id="resource.TAbstractResource.RawData">RawData</link>, and the list and its contents must be freed:</p>
+<code>
+procedure TAcceleratorsResource.UpdateRawData;
+var acc : TAccelerator;
+    i : integer;
+begin
+  if fList=nil then exit;
+  RawData.Size:=0;
+  RawData.Position:=0;
+
+  for i:=0 to fList.Count-1 do
+  begin
+    acc:=PAccelerator(fList[i])^;
+    // $80 means 'this is the last entry', so be sure only the last one has this bit set.
+    if i=Count-1 then acc.Flags:=acc.Flags or $80
+    else acc.Flags:=acc.Flags and $7F;
+    RawData.WriteBuffer(acc,sizeof(acc));
+  end;
+  Clear;
+  FreeAndNil(fList);
+end;	
+</code>
+<p>If <var>fList</var> is <var>nil</var> data hasn't been loaded, so <link id="resource.TAbstractResource.RawData">RawData</link> is up to date, so exit. Otherwise, write each accelerator (ensuring that only last one has <var>$80</var> flag set), clear the list, free it and set it to nil. Again, if we are on a big endian system we should swap each accelerator contents before writing it, but for simplicity this is omitted.</p>
+<p>Other methods we named earlier (<var>Add</var>, <var>Delete</var>, <var>Clear</var>) are trivial to implement: remember only to call <var>CheckDataLoaded</var> before doing anything. The same is true for accessor methods of relevant properties (<var>Count</var>, <var>Items</var>).</p>
+<p>If you are curious, you can check the full implementation of <link id="acceleratorsresource.TAcceleratorsResource">TAcceleratorsResource</link> looking at source code.</p>
+</descr>
+</topic>
+
+<topic name="Basic Usage">
+<short>Basic Usage</short>
+<descr>
+<p><b>Resource files and TResources class</b></p>
+<p>One of the most important classes is <link id="resource.TResources">TResources</link> class, contained in <link id="resource"/> unit, which represents a format-independent view of a resource file. In fact, while single resources are important, they are of little use alone, since they can't be read or written to file directly: they need to be contained in a <link id="resource.TResources">TResources</link> object.</p>
+<p><link id="resource.TResources">TResources</link> provides methods to read itself from a file or stream, using specific objects that are able to read resource data from such a stream: these are the so called <i>resource readers</i>, that descend from <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link>.</p>
+<p>There are also <i>resource writers</i> that do the opposite, and that descend from <link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link>.</p>
+<p>Usually readers and writers register themselves with <link id="resource.TResources">TResources</link> in the <var>initialization</var> section of the unit they are implemented in, so you only need to add a certain unit to your program <var>uses</var> clause to let <link id="resource.TResources">TResources</link> "know" about a particular file format.</p>
+<p>Let's see a very simple example: a program that converts a .res file to an object file in COFF format (the object file format used by Microsoft Windows).</p>
+<code>
+program res1;
+
+{$mode objfpc}
+
+uses
+  Classes, SysUtils, resource, resreader, coffwriter;
+
+var
+  resources : TResources;
+begin
+  resources:=TResources.Create;
+  resources.LoadFromFile('myresource.res');
+  resources.WriteToFile('myobject.o');
+  resources.Free;
+end.
+</code>
+<p>As you can see, the code is trivial. Note that <var>resreader</var> and <var>coffwriter</var> units were added to the <var>uses</var> clause of the program: this way, the resource reader for .res files and the resource writer for COFF files have been registered, letting the <var>resources</var> object know how to handle these file types.</p>
+<p>There are cases where one doesn't want to let the <link id="resource.TResources">TResources</link> object to choose readers and writers by itself. In fact, while generally it is a good idea to let <link id="resource.TResources">TResources</link> probe all readers it knows to find one able to read the input file, this isn't true when it comes to write files: writers are selected based on the file extension, so if you are trying to write a file with .o extension you can't be sure about which writer will be selected: it could be the COFF or the ELF writer (it depends on which writer gets registered first). Moreover, writers generally make an object file for the host architecture, so if you are running the program on a i386 machine it will produce a COFF or ELF file for i386.</p>
+<p>The solution is to provide <link id="resource.TResources">TResources</link> with a specific writer. In the following example the reader is automatically chosen among various readers, and we use a specific writer to produce an ELF file for SPARC.</p>
+<code>
+program res2;
+
+{$mode objfpc}
+
+uses
+  Classes, SysUtils, resource,
+  resreader, coffreader, elfreader, winpeimagereader, //readers
+  elfwriter, elfconsts;
+
+var
+  resources : TResources;
+  writer : TElfResourceWriter;
+begin
+  resources:=TResources.Create;
+  resources.LoadFromFile(paramstr(1));
+  writer:=TElfResourceWriter.Create;
+  writer.MachineType:=emtsparc;
+  resources.WriteToFile(ChangeFileExt(paramstr(1),'.o'),writer);
+  resources.Free;
+  writer.Free;
+end.
+</code>
+<p>Note that the file to convert is taken from the command line. Its format is automatically detected among res (<link id="resreader"/>), coff (<link id="coffreader"/>), elf (<link id="elfreader"/>), PE (<link id="winpeimagereader"/>, e.g. a Windows exe or dll), and is written as an ELF file for SPARC. Note that we had to use <link id="elfconsts"/> unit since we used <link id="elfconsts.TElfMachineType.emtsparc">emtsparc</link> constant to specify the machine type of the object file to generate.</p>
+<p>With a small change to the above program we can let the user know which reader was selected to read the input file: we can use <link id="resource.TResources.FindReader">TResources.FindReader</link> class method to obtain the appropriate reader for a given stream.</p>
+<code>
+program res3;
+
+{$mode objfpc}
+
+uses
+  Classes, SysUtils, resource,
+  resreader, coffreader, elfreader, winpeimagereader, //readers
+  elfwriter, elfconsts;
+
+var
+  resources : TResources;
+  writer : TElfResourceWriter;
+  reader : TAbstractResourceReader;
+  inFile : TFileStream;
+begin
+  resources:=TResources.Create;
+  inFile:=TFileStream.Create(paramstr(1), fmOpenRead or fmShareDenyNone);
+  reader:=TResources.FindReader(inFile);
+  writeln('Selected reader: ',reader.Description);
+  resources.LoadFromStream(inFile,reader);
+  writer:=TElfResourceWriter.Create;
+  writer.MachineType:=emtsparc;
+  resources.WriteToFile(ChangeFileExt(paramstr(1),'.o'),writer);
+  resources.Free;
+  reader.Free;
+  writer.Free;
+  inFile.Free;
+end.
+</code>
+<p>Output example:</p>
+<pre>
+user@localhost:~$ ./res3 myresource.res
+Selected reader: .res resource reader
+user@localhost:~$
+</pre>
+<p><b>Single resources</b></p>
+<p>You can do more with resources than simply converting between file formats.</p>
+<p><link id="resource.TResources.Items">TResources.Items</link> property provides a simple way to access all resources contained in the <link id="resource.TResources">TResources</link> object.</p>
+<p>In the following example we read a resource file and then dump each resource data in a file whose name is built from type and name of the dumped resource.</p>
+<code>
+program res4;
+
+{$mode objfpc}
+
+uses
+  Classes, SysUtils, resource, resreader;
+
+var
+  resources : TResources;
+  dumpFile : TFileStream;
+  i : integer;
+  fname : string;
+begin
+  resources:=TResources.Create;
+  resources.LoadFromFile('myresource.res');
+  for i:=0 to resources.Count-1 do
+  begin
+    fname:=resources[i]._Type.Name+'_'+resources[i].Name.Name;
+    dumpFile:=TFileStream.Create(fname,fmCreate or fmShareDenyWrite);
+    dumpFile.CopyFrom(resources[i].RawData,resources[i].RawData.Size);
+    dumpFile.Free;
+  end;
+  resources.Free;
+end.
+</code>
+<p>This code simply copies the content of each resource's <link id="resource.TAbstractResource.RawData">RawData</link> stream to a file stream, whose name is <i>resourcetype_resourcename</i>.</p>
+<p>Resource raw data isn't always what one expected, however. While some resource types simply contain a copy of a file in their raw data, other types do some processing, so that dumping raw data doesn't result in a file in the format one expected.</p>
+<p>E.g. a resource of type <link id="resource.RT_MANIFEST">RT_MANIFEST</link> is of the former type: its raw data is like an XML manifest file. On the other hand, in a resource of type <link id="resource.RT_BITMAP">RT_BITMAP</link> the <link id="resource.TAbstractResource.RawData">RawData</link> stream isn't like a BMP file.</p>
+<p>For this reason, several classes (descendants of <link id="resource.TAbstractResource">TAbstractResource</link>) are provided to handle the peculiarities of this or that resource type. Much like it's done with readers and writers, resource classes can be registered: adding the unit that contains a resource class to the <var>uses</var> clause of your program registers that class. This way, when resources are read from a file, they are created with the class that is registered for their type (the class responsible to do this is <link id="resfactory.TResourceFactory">TResourceFactory</link>, but probably you won't need to use it unless you're implementing a new resource reader or resource class).</p>
+<p>In the following example, we read a resource file and then dump data of each resource of type <link id="resource.RT_BITMAP">RT_BITMAP</link> as a BMP file.</p>
+<code>
+program res5;
+
+{$mode objfpc}
+
+uses
+  Classes, SysUtils, resource, resreader, bitmapresource;
+
+var
+  resources : TResources;
+  dumpFile : TFileStream;
+  i : integer;
+  fname : string;
+begin
+  resources:=TResources.Create;
+  resources.LoadFromFile('myresource.res');
+  for i:=0 to resources.Count-1 do
+    if resources[i] is TBitmapResource then
+      with resources[i] as TBitmapResource do
+      begin
+        fname:=Name.Name+'.bmp';
+        dumpFile:=TFileStream.Create(fname,fmCreate or fmShareDenyWrite);
+        dumpFile.CopyFrom(BitmapData,BitmapData.Size);
+        dumpFile.Free;
+      end;
+  resources.Free;
+end.
+</code>
+<p>Note that we included <link id="bitmapresource"/> in the <var>uses</var> clause of our program. This way, resources of type <link id="resource.RT_BITMAP">RT_BITMAP</link> are created from <link id="bitmapresource.TBitmapResource">TBitmapResource</link> class. This class provides a stream, <link id="bitmapresource.TBitmapResource.BitmapData">BitmapData</link> that allows resource raw data to be accessed as if it was a bmp file.</p>
+<p>We can of course do the opposite. In the following code we are creating a manifest resource from <var>manifest.xml</var> file.</p>
+<code>
+program res6;
+
+{$mode objfpc}
+
+uses
+  Classes, SysUtils, resource, reswriter;
+
+var
+  resources : TResources;
+  inFile : TFileStream;
+  res : TGenericResource;
+  rname,rtype : TResourceDesc;
+begin
+  inFile:=TFileStream.Create('manifest.xml',fmOpenRead or fmShareDenyNone);
+  rtype:=TResourceDesc.Create(RT_MANIFEST);
+  rname:=TResourceDesc.Create(1);
+  res:=TGenericResource.Create(rtype,rname);
+  rtype.Free; //no longer needed
+  rname.Free;
+  res.SetCustomRawDataStream(inFile);
+  resources:=TResources.Create;
+  resources.Add(res);
+  resources.WriteToFile('myresource.res');
+  resources.Free;  //frees res as well
+  inFile.Free;
+end.
+</code>
+<p>Note that resources of type <link id="resource.RT_MANIFEST">RT_MANIFEST</link> contain a straight copy of a xml file, so <link id="resource.TGenericResource">TGenericResource</link> class fits our needs. <link id="resource.TGenericResource">TGenericResource</link> is a basic implementation of <link id="resource.TAbstractResource">TAbstractResource</link>. It is the default class used by <link id="resfactory.TResourceFactory">TResourceFactory</link> when it must create a resource whose type wasn't registered with any resource class.</p>
+<p>Please note that instead of copying <var>inFile</var> contents to <link id="resource.TAbstractResource.RawData">RawData</link> we used <link id="resource.TAbstractResource.SetCustomRawDataStream">SetCustomRawDataStream</link> method: it sets a stream as the underlying stream for <link id="resource.TAbstractResource.RawData">RawData</link>, so that when final resource file is written, data is read directly from the original file.</p>
+<p>Let's see a similar example, in which we use a specific class instead of <link id="resource.TGenericResource">TGenericResource</link>. In the following code we are creating a resource containing the main program icon, which is read from <var>mainicon.ico</var> file.</p>
+<code>
+program res7;
+
+{$mode objfpc}
+
+uses
+  Classes, SysUtils, resource, reswriter, groupiconresource;
+
+var
+  resources : TResources;
+  inFile : TFileStream;
+  iconres : TGroupIconResource;
+  name : TResourceDesc;
+begin
+  inFile:=TFileStream.Create('mainicon.ico',fmOpenRead or fmShareDenyNone);
+  name:=TResourceDesc.Create('MAINICON');
+  //type is always RT_GROUP_ICON for this resource class
+  iconres:=TGroupIconResource.Create(nil,name);
+  iconres.SetCustomItemDataStream(inFile);
+  resources:=TResources.Create;
+  resources.Add(iconres);
+  resources.WriteToFile('myicon.res');
+  resources.Free;  //frees iconres as well
+  inFile.Free;
+  name.Free;
+end.
+</code>
+<p>In this program we created a new <link id="groupiconresource.TGroupIconResource">TGroupIconResource</link> with 'MAINICON' as name, and we loaded its contents from file 'mainicon.ico'. Please note that <link id="resource.RT_GROUP_ICON">RT_GROUP_ICON</link> resource raw data doesn't contain a .ico file, so we have to write to <link id="groupresource.TGroupResource.ItemData">ItemData</link> which is a ico-like stream. As we did for <var>res6</var> program, we tell the resource to use our stream as the underlying stream for resource data: the only difference is that we are using <link id="groupresource.TGroupResource.SetCustomItemDataStream">TGroupResource.SetCustomItemDataStream</link> instead of <link id="resource.TAbstractResource.SetCustomRawDataStream">TAbstractResource.SetCustomRawDataStream</link> method, for obvious reasons.</p>
+<p><b>Other resource types</b></p>
+<p>There are other resource types that allow to easily deal with resource data. E.g. <link id="versionresource.TVersionResource">TVersionResource</link> makes it easy to create and read version information for Windows executables and dlls, <link id="stringtableresource.TStringTableResource">TStringTableResource</link> deals with string tables, and so on.</p>
+<p><b>Data caching</b></p>
+<p>Whenever possible, fcl-res tries to avoid to duplicate data. Generally a reader doesn't copy resource data from the original stream to <link id="resource.TAbstractResource.RawData">RawData</link> stream: instead, it only informs the resource about where its raw data is in the original stream. <link id="resource.TAbstractResource.RawData">RawData</link> uses a caching system so that it appears as a stream while it only redirects operations to its underlying stream, with a copy-on-write mechanism. Of course this behaviour can be controlled by the user. For further information, see <link id="resource.TAbstractResource">TAbstractResource</link> and <link id="resource.TAbstractResource.RawData">TAbstractResource.RawData</link>.</p>
+</descr>
+
+</topic>
+
+<topic name="Introduction">
+<short>Introduction</short>
+<descr>
+<p>This package contains a library to easily work with Microsoft Windows resources in a cross-platform way.</p>
+<p>Classes are provided to create, load and write resources from/to different file formats in a transparent way, and to handle most common resource types without having to deal with their internal format.</p>
+<p>Whenever possible data caching is performed, helped by a copy-on-write mechanism. This improves performance especially when converting big resources from a file format to another.</p>
+<p>Since fcl-res architecture is extensible, it's always possible to extend the library with custom resource types or new file readers/writers.</p>
+<p>Please note that resources aren't limited to Windows platform: Free Pascal can use them also on ELF and Mach-O targets. Moreover, this library can be useful for cross-compilation purposes even on other targets.</p>
+<p>It is highly recommended to read <link id="Basic Usage"/> topic if you are approaching this library for the first time.</p>
+</descr>
+</topic>
+
+<!--
+  ====================================================================
+    resource
+  ====================================================================
+-->
+
+<module name="resource">
+<short>Contains base classes for resource handling</short>
+<descr>
+<p>This unit contains base classes needed to work with resources.</p>
+<p>Single resources are represented by an instance of a <link id="TAbstractResource"/> descendant. They are grouped in a <link id="TResources"/> instance which can be read (written) to (from) a stream via a <link id="TAbstractResourceReader"/> (<link id="TAbstractResourceWriter"/>) descendant.</p>
+<p><link id="TGenericResource"/> provides a basic implementation of <link id="TAbstractResource"/>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Sysutils">
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_CURSOR">
+<short>Single cursor resource</short>
+<descr>
+A single image in a cursor. Don't use it directly.
+</descr>
+<seealso>
+<link id="RT_GROUP_CURSOR"/>
+<link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_BITMAP">
+<short>Bitmap resource</short>
+<seealso>
+<link id="bitmapresource.TBitmapResource">TBitmapResource</link>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_ICON">
+<short>Single icon resource</short>
+<descr>
+A single image in a icon. Don't use it directly.
+</descr>
+<seealso>
+<link id="RT_GROUP_ICON"/>
+<link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_MENU">
+<short>Menu resource</short>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_DIALOG">
+<short>Dialog resource</short>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_STRING">
+<short>String table resource</short>
+<seealso>
+<link id="stringtableresource.TStringTableResource">TStringTableResource</link>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_FONTDIR">
+<short>Font directory resource</short>
+<descr>
+This resource type is obsolete and never appears in 32 bit resources.
+</descr>
+<seealso>
+<link id="RT_FONT"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_FONT">
+<short>Single font resource</short>
+<descr>
+This resource type is obsolete and never appears in 32 bit resources.
+</descr>
+<seealso>
+<link id="RT_FONTDIR"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_ACCELERATOR">
+<short>Accelerator table resource</short>
+<seealso>
+<link id="acceleratorsresource.TAcceleratorsResource">TAcceleratorsResource</link>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_RCDATA">
+<short>Application-defined resource (raw data)</short>
+<descr>
+<p>This resource type contains arbitrary binary data</p>
+<p>Note that Delphi dfm files are stored in compiled form as a RCDATA resource</p>
+</descr>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_MESSAGETABLE">
+<short>Message table resource</short>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_GROUP_CURSOR">
+<short>Cursor resource</short>
+<descr>
+<p>This resource type contains a cursor and it's the equivalent of a .cur file</p>
+<remark>Please note that is is made up of several <link id="RT_CURSOR"/> resources (the single cursor images) that shouldn't be accessed singularly.</remark>
+</descr>
+<seealso>
+<link id="RT_CURSOR"/>
+<link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_GROUP_ICON">
+<short>Icon resource</short>
+<descr>
+<p>This resource type contains an icon and it's the equivalent of a .ico file</p>
+<remark>Please note that is is made up of several <link id="RT_ICON"/> resources (the single icon images) that shouldn't be accessed singularly.</remark>
+</descr>
+<seealso>
+<link id="RT_ICON"/>
+<link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_VERSION">
+<short>Version resource</short>
+<descr>
+This resource defines version information which is visible when viewing properties of a Windows executable or DLL.
+</descr>
+<seealso>
+<link id="versionresource.TVersionResource">TVersionResource</link>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_DLGINCLUDE">
+<short>Never present in compiled form</short>
+<descr>
+This resource is used internally by resource compilers but will never appear in compiled form
+</descr>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_PLUGPLAY">
+<short>Plug and Play resource</short>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_VXD">
+<short>VXD resource</short>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_ANICURSOR">
+<short>Animated cursor resource</short>
+<descr>
+This resource type contains raw binary data taken from a .ani file
+</descr>
+<seealso>
+<link id="RT_ANIICON"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_ANIICON">
+<short>Animated icon resource</short>
+<descr>
+This resource type contains raw binary data taken from a .ani file
+</descr>
+<seealso>
+<link id="RT_ANICURSOR"/>
+</seealso>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_HTML">
+<short>HTML resource</short>
+<descr>
+This resource type contains an HTML file.
+</descr>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="RT_MANIFEST">
+<short>Windows XP Side-by-Side Assembly XML manifest</short>
+<descr>
+<p>This resource contains data taken from a .manifest file</p>
+<remark>Resource name must be one of <link id ="CREATEPROCESS_MANIFEST_RESOURCE_ID"/> (mainly used for executables), <link id ="ISOLATIONAWARE_MANIFEST_RESOURCE_ID"/> or <link id="ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID"/> (mainly used for DLLs)</remark>
+</descr>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="CREATEPROCESS_MANIFEST_RESOURCE_ID">
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ISOLATIONAWARE_MANIFEST_RESOURCE_ID">
+</element>
+
+<!-- constant Visibility: default -->
+<element name="ISOLATIONAWARE_NOSTATICIMPORT_MANIFEST_RESOURCE_ID">
+</element>
+
+<!-- constant Visibility: default -->
+<element name="MINIMUM_RESERVED_MANIFEST_RESOURCE_ID">
+</element>
+
+<!-- constant Visibility: default -->
+<element name="MAXIMUM_RESERVED_MANIFEST_RESOURCE_ID">
+</element>
+
+<!-- constant Visibility: default -->
+<element name="MF_MOVEABLE">
+<short>The resource can be moved</short>
+<descr>
+This flag is ignored by Windows and Free Pascal RTL. It's provided for compatibility with 16-bit Windows.
+</descr>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="MF_PURE">
+<short>The resource contains dword-aligned data</short>
+<descr>
+This flag is ignored by Windows and Free Pascal RTL. It's provided for compatibility with 16-bit Windows.
+</descr>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="MF_PRELOAD">
+<short>The resource is loaded with the executable file</short>
+<descr>
+This flag is ignored by Windows and Free Pascal RTL. It's provided for compatibility with 16-bit Windows.
+</descr>
+</element>
+
+<!-- constant Visibility: default -->
+<element name="MF_DISCARDABLE">
+<short>The resource can be discarded if no longer needed</short>
+<descr>
+This flag is ignored by Windows and Free Pascal RTL. It's provided for compatibility with 16-bit Windows.
+</descr>
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SReaderNotFoundExt">
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SReaderNotFoundProbe">
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SWriterNotFoundExt">
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SDescChangeNotAllowed">
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SLangIDChangeNotAllowed">
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SResDuplicate">
+</element>
+
+<!-- alias type Visibility: default -->
+<element name="TLangID">
+<short>A resource language ID</short>
+</element>
+
+<!-- alias type Visibility: default -->
+<element name="TResName">
+<short>A resource type or name in string form</short>
+<seealso>
+<link id="TResID"/>
+<link id="TDescType"/>
+<link id="TResourceDesc"/>
+</seealso>
+</element>
+
+<!-- alias type Visibility: default -->
+<element name="TResID">
+<short>A resource type or name in ID form</short>
+<seealso>
+<link id="TResName"/>
+<link id="TDescType"/>
+<link id="TResourceDesc"/>
+</seealso>
+</element>
+
+<!-- enumeration type Visibility: default -->
+<element name="TDescType">
+<short>The type of a resource type or name</short>
+<seealso>
+<link id="TResName"/>
+<link id="TResID"/>
+<link id="TResourceDesc"/>
+</seealso>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TDescType.dtName">
+<short>The resource type or name is a string</short>
+</element>
+
+<!-- enumeration value Visibility: default -->
+<element name="TDescType.dtID">
+<short>The resource type or name is an ID</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceException">
+<short>Base class for resource-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceDescTypeException">
+<short>Wrong description type error</short>
+<descr>
+<p>This exception is raised when a resource description is of type <link id="TDescType.dtName">dtName</link> and <link id="TResourceDesc.ID"/> property is read.</p>
+</descr>
+<seealso>
+<link id="TResourceDesc.ID"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceDescChangeNotAllowedException">
+<short>Description is not allowed to change</short>
+<descr>
+<p>This exception is raised when a resource description (either type or name) is tried to be changed, but the resource class doesn't allow it.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource._Type"/>
+<link id="TAbstractResource.Name"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceLangIDChangeNotAllowedException">
+<short>Language ID is not allowed to change</short>
+<descr>
+<p>This exception is raised when the resource language ID is tried to be changed, but the resource is contained in a <link id="TResources"/> object.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource.LangID"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceDuplicateException">
+<short>There is already a resource with same type, name and language ID</short>
+<descr>
+<p>This exception is raised when a resource is being added to a <link id="TResources"/> object, but another resource with the same type, name and language ID already exists.</p>
+</descr>
+<seealso>
+<link id="TResources.Add"/>
+<link id="TResources.MoveFrom"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceNotFoundException">
+<short>No resource matching the search criteria is found</short>
+<descr>
+<p>This exception is raised when searching for a resource in a <link id="TResources"/> object fails.</p>
+</descr>
+<seealso>
+<link id="TResources.Find"/>
+<link id="TResources.Remove"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="ENoMoreFreeIDsException">
+<short>There are no more free IDs to use as name for a resource</short>
+<descr>
+<p>This exception is raised by <link id="TResources.AddAutoID"/> method when it is not possible to generate an ID to use as a name for the given resource, because all possible 65536 IDs are already assigned to resources of the same type as the given one.</p>
+</descr>
+<seealso>
+<link id="TResources.AddAutoID"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceReaderException">
+<short>Base class for resource reader-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceReaderNotFoundException">
+<short>No suitable resource reader was found</short>
+<descr>
+<p>This exception is raised when no <link id="TAbstractResourceReader"/> descendant able to read a stream was found.</p>
+</descr>
+<seealso>
+<link id="TResources.FindReader"/>
+<link id="TResources.LoadFromStream"/>
+<link id="TResources.LoadFromFile"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceReaderWrongFormatException">
+<short>The stream is not in the format the reader supports</short>
+<descr>
+<p>This exception is raised by <link id="TAbstractResourceReader.Load">Load</link> method of a <link id="TAbstractResourceReader"/> descendant when the stream it was asked to read resources from is not in the format it supports.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.Load"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceReaderUnexpectedEndOfStreamException">
+<short>The stream ended prematurely</short>
+<descr>
+<p>This exception is raised by <link id="TAbstractResourceReader.Load">Load</link> method of a <link id="TAbstractResourceReader"/> descendant when the stream it was asked to read resources from ended prematurely.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.Load"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceWriterException">
+<short>Base class for resource writer-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EResourceWriterNotFoundException">
+<short>No suitable resource writer was found</short>
+<descr>
+<p>This exception is raised by <link id="TResources.WriteToFile">WriteToFile</link> method of <link id="TResources"/> when no <link id="TAbstractResourceWriter"/> descendant matching filename extension was found.</p>
+</descr>
+<seealso>
+<link id="TResources.WriteToFile"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TAbstractResource">
+<short>Base abstract resource class</short>
+<descr>
+<p>This is the base class that represents a resource.</p>
+<p>A resource is identified by its <link id="TAbstractResource._Type">type</link>, <link id="TAbstractResource.Name">name</link> and <link id="TAbstractResource.LangID">language ID</link> even if some file formats or operating systems don't consider the latter.</p>
+<p>There are also additional properties that aren't always present in all file formats, so their values aren't always meaningful: however, they can be used to display detailed information when possible.</p>
+<p>Every resource has a <link id="TAbstractResource.RawData">RawData</link> stream that holds resource data. This stream uses a copy-on-write mechanism: if the resource has been read from a stream or file, <link id="TAbstractResource.RawData">RawData</link> redirects read operations to the original stream. This is particularly useful when a resource file must be converted from a format to another, or when more resource files must be merged, since (potentially large) resource data is directly copied from the original to the destination stream without the need of allocating a lot of memory.</p>
+<p>When resource data is encoded in a resource-specific format, <link id="TAbstractResource.RawData">RawData</link> can be uncomfortable: it's often better to use a more specialized descendant class that provides additional properties and methods.</p>
+<p>Resources cannot be read or written alone from/to a stream: they need to be contained in a <link id="TResources"/> object, which represents an abstract view of a resource file.</p>
+<p>Usually each descendant registers itself with <link id="resfactory.TResourceFactory">TResourceFactory</link> class in the <var>initialization</var> section of the unit in which it is implemented: this way <link id="resfactory.TResourceFactory">TResourceFactory</link> class can know which class to use to instantiate a resource of a given type.</p>
+<remark>An object of this class should never be directly instantiated: use a descendant class instead.</remark>
+</descr>
+<seealso>
+<link id="TGenericResource"/>
+<link id="acceleratorsresource.TAcceleratorsResource">TAcceleratorsResource</link>
+<link id="bitmapresource.TBitmapResource">TBitmapResource</link>
+<link id="groupcursorresource.TGroupCursorResource">TGroupCursorResource</link>
+<link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>
+<link id="stringtableresource.TStringTableResource">TStringTableResource</link>
+<link id="versionresource.TVersionResource">TVersionResource</link>
+<link id="TResources"/>
+<link id="resfactory.TResourceFactory">TResourceFactory</link>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TResourceDesc">
+<short>A resource description (type or name)</short>
+<descr>
+<p>This class represent a resource description (type or name).</p>
+<p>Resources are identified by a type, name and (optionally) a language ID.</p>
+<p>Type and name can be either a <b>name</b> (a string identifier) or an <b>ID</b> (an integer identifier in the range 0..65535).</p>
+<remark>
+Unfortunately, <i>name</i> is used both to refer to a the name of the resource and both to the format of a resource description
+</remark>
+<p><b>Example:</b></p>
+<p>Typically, a Windows executable has a main icon, which is a resource of type <link id ="RT_GROUP_ICON"/> (type is an ID) and name <var>MAINICON</var> (name is a name).</p>
+</descr>
+<seealso>
+<link id="TAbstractResource"/>
+</seealso>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TResourceDesc.SetOwner">
+<short>Protected method to let a resource set itself as owner of the TResourceDesc</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDesc.SetOwner.aOwner">
+<short>The resource that is to become the owner of the TResourceDesc</short>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TResourceDesc.Create">
+<short>Creates a new TResourceDesc object</short>
+<descr>
+<p>Creates a new TResourceDesc object.</p>
+<p>Without arguments, resource description is of type <link id="TDescType.dtName">dtName</link> and its name is empty.</p>
+<p>If an argument is specified, resource description and name/id are set accordingly to the value passed as parameter.</p>
+</descr>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDesc.Create.aID">
+<short>The ID to use as the resource description ID</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDesc.Create.aName">
+<short>The name to use as the resource description name</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResourceDesc.Assign">
+<short>Assigns the contents of another TResourceDesc object to this one</short>
+<descr>
+</descr>
+<errors>
+<p>
+If changing values is not permitted because owner resource doesn't allow it (e.g. because owner resource is a <link id="bitmapresource.TBitmapResource">TBitmapResource</link> and values other than <link id ="RT_BITMAP"/> are not permitted for the resource type) an <link id="EResourceDescChangeNotAllowedException"/> exception is raised.</p>
+</errors>
+<seealso>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDesc.Assign.aResourceDesc">
+<short>The object from which data must be copied</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceDesc.Equals">
+<short>Compares the contents of another TResourceDesc object to this one</short>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceDesc.Equals.Result">
+<short>True if the contents of the two objects are the same</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceDesc.Equals.aResDesc">
+<short>The object to compare with this one</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceDesc.Name">
+<short>The value of the resource description as a name</short>
+<descr>
+<p>Setting this property causes <link id="TResourceDesc.DescType">DescType</link> to be <link id="TDescType.dtName">dtName</link></p>
+<p>When reading, if <link id="TResourceDesc.DescType">DescType</link> is <link id="TDescType.dtID">dtID</link>, the ID is returned as a string value.</p>
+</descr>
+<seealso>
+<link id="TResourceDesc.ID"/>
+<link id="TResourceDesc.DescType"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceDesc.ID">
+<short>The value of the resource description as an ID</short>
+<descr>
+<p>Setting this property causes <link id="TResourceDesc.DescType">DescType</link> to be <link id="TDescType.dtID">dtID</link></p>
+<remark>When reading, if <link id="TResourceDesc.DescType">DescType</link> is <link id="TDescType.dtName">dtName</link>, an <link id="EResourceDescTypeException"/> exception is raised.</remark>
+</descr>
+<seealso>
+<link id="TResourceDesc.Name"/>
+<link id="TResourceDesc.DescType"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceDesc.DescType">
+<short>The type of the resource description</short>
+<descr>
+<p>When DescType is <link id="TDescType.dtName">dtName</link>, resource description value is a name and can be accessed via <link id="TResourceDesc.Name">Name</link> property</p>
+<p>When DescType is <link id="TDescType.dtID">dtID</link>, resource description value is an ID and can be accessed via <link id="TResourceDesc.ID">ID</link> property</p>
+</descr>
+<seealso>
+<link id="TResourceDesc.Name"/>
+<link id="TResourceDesc.ID"/>
+<link id="TDescType"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TResources">
+<short>A collection of resources</short>
+<descr>
+<p>This class represents a format-independent view of a resource file. It holds a collection of resources (<link id="TAbstractResource"/> descendants).</p>
+<p>Typically, a TResource object is loaded from and written to a stream via format-dependent readers and writers, which are descendants of <link id="TAbstractResourceReader"/> and <link id="TAbstractResourceWriter"/>, respectively.</p>
+<p>Single resources can be added, removed, searched and modified: a resource compiler or editor probably will create resources, set their data, and add them to a TResources object which can then be written to file in the desired format.</p>
+<p>This class also provides some class methods to register and find resource readers and writers: these classes, once registered, will be used by a TResources object when it is asked to load or save itself to a stream and the user didn't specify a reader or writer.</p>
+<remark>Because of the copy-on-write mechanism of <link id="TAbstractResource"/>, care should be taken when loading resources, since by default resource data isn't immediately read from the stream: resources hold a reference to the original stream because they need it when their data is requested. For further information, see <link id="TResources.LoadFromStream"/> and <link id="TResources.LoadFromFile"/>.</remark>
+</descr>
+<seealso>
+<link id="TAbstractResource"/>
+<link id="TAbstractResourceReader"/>
+<link id="TAbstractResourceWriter"/>
+</seealso>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResource.SetDescOwner">
+<short>Sets this resource as the owner of the given TResourceDesc</short>
+<descr>
+<p>This method is provided so that descendants of <link id="TAbstractResource"/> can set themselves as the owners of the given TResourceDesc</p>
+</descr>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.SetDescOwner.aDesc">
+<short>The TResourceDesc that the resource must own</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResource.SetOwnerList">
+<short>Protected method to let a resource list set itself as the owner of the resource</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.SetOwnerList.aResources">
+<short>The resource list that is to become the owner of the resource</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResource.SetChildOwner">
+<short>Protected method to let a resource set itself as the owner of a sub-resource</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.SetChildOwner.aChild">
+<short>The sub-resource that the resource must own</short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResource.GetType">
+<short>Returns the type of the resource</short>
+<descr>
+<p>Descendant classes must implement this method to provide access to the resource type.</p>
+</descr>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResource.GetType.Result">
+<short>The <link id="TResourceDesc"/> object representing the type of the resource</short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResource.GetName">
+<short>Returns the name of the resource</short>
+<descr>
+<p>Descendant classes must implement this method to provide access to the resource name.</p>
+</descr>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResource.GetName.Result">
+<short>The <link id="TResourceDesc"/> object representing the name of the resource</short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResource.ChangeDescTypeAllowed">
+<short>Reports whether changing the type of resource type or name is allowed</short>
+<descr>
+<p>Descendant classes must implement this method to declare if the resource allows changing the type of one of its resource description (type or name): that is, if it allows one of its descriptions type to change from <link id="TDescType.dtName">dtName</link> to <link id="TDescType.dtID">dtID</link> or vice versa.</p>
+<p><b>Example:</b></p>
+<p>A certain resource class allows its name only to be changed: e.g. a <link id="bitmapresource.TBitmapResource">TBitmapResource</link> doesn't want its type to be anything else than <link id="RT_BITMAP"/>. It then allows changing the type of the description only if the description is the resource name:</p>
+<code>
+  Result:=aDesc=fName;
+</code>
+</descr>
+<seealso>
+<link id="TAbstractResource.ChangDescValueAllowed"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResource.ChangeDescTypeAllowed.Result">
+<short>True if the resource allows the given <link id="TResourceDesc"/> to change type</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.ChangeDescTypeAllowed.aDesc">
+<short>The <link id="TResourceDesc"/> whose type should be changed</short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResource.ChangeDescValueAllowed">
+<short>Reports whether changing the value of resource type or name is allowed</short>
+<descr>
+<p>Descendant classes must implement this method to declare if the resource allows changing the value of one of its resource description (type or name).</p>
+<p><b>Example:</b></p>
+<p>A certain resource class allows its name only to be changed: e.g. a <link id="bitmapresource.TBitmapResource">TBitmapResource</link> doesn't want its type to be anything else than <link id="RT_BITMAP"/>. It then allows changing the value of the description only if the description is the resource name:</p>
+<code>
+  Result:=aDesc=fName;
+</code>
+</descr>
+<seealso>
+<link id="TAbstractResource.ChangDescTypeAllowed"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResource.ChangeDescValueAllowed.Result">
+<short>True if the resource allows the given <link id="TResourceDesc"/> to change value</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.ChangeDescValueAllowed.aDesc">
+<short>The <link id="TResourceDesc"/> whose value should be changed</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResource.NotifyResourcesLoaded">
+<short>Tells the resource that all resources have been loaded</short>
+<descr>
+<p>This method is called by a <link id="TResources"/> object when the loading of all resources from a stream has completed.</p>
+<p><b>Example:</b></p>
+<p>A Group resource (e.g. <link id="groupiconresource.TGroupIconResource">TGroupIconResource</link>) can use this method to find all its sub-resources, since all resources have been loaded from a stream.</p>
+</descr>
+</element>
+
+<!-- constructor Visibility: protected -->
+<element name="TAbstractResource.Create">
+<short>Creates a new resource</short>
+<descr>
+<p>A new resource is created with the given type and name.</p>
+<remark>Please note that the resource doesn't take ownership of the <link id="TResourceDesc"/> objects passed as parameters, it simply copies them: it's user responsibility to free them when no longer needed.</remark>
+</descr>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.Create.aType">
+<short>The type of the resource to be created</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.Create.aName">
+<short>The name of the resource to be created</short>
+</element>
+
+<!-- destructor Visibility: public -->
+<element name="TAbstractResource.Destroy">
+<short>Destroys the object</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TAbstractResource.CompareContents">
+<short>Compares the contents of the resource to the contents of another one</short>
+<descr>
+<p>This methods compares the contents of the resource with the ones of <var>aResource</var>. If they are of the same length and their contents are the same, <var>true</var> is returned, <var>false</var> otherwise.</p>
+<p>Usually this methods compares the contents of the two <link id="TAbstractResource.RawData">RawData</link> streams, calling <link id="resdatastream.TResourceDataStream.Compare">TResourceDataStream.Compare</link>, but descendent classes can implement a different algorithm.</p>
+</descr>
+<seealso>
+<link id="resdatastream.TResourceDataStream.Compare">TResourceDataStream.Compare</link>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResource.CompareContents.Result">
+<short>True if the contents of the two resources are the same</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.CompareContents.aResource">
+<short>The resource to compare to this one</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TAbstractResource.UpdateRawData">
+<short>Updates RawData stream.</short>
+<descr>
+<p>When operating on resource data with more high-level streams than <link id="TAbstractResource.RawData">RawData</link> (e.g: <link id="bitmapresource.TBitmapResource.BitmapData">TBitmapResource.BitmapData</link>) RawData contents are no longer valid. This method ensures that <link id="TAbstractResource.RawData">RawData</link> stream is properly synchronized with the contents of the higher-level stream.</p>
+<remark>Normally a resource writer doesn't need to call this method when it is about to write the resource data to a stream, since <link id="TResources"/> class takes care of this before telling the resource writer to write resources to a stream.</remark>
+</descr>
+<seealso>
+<link id="TAbstractResource.RawData"/>
+</seealso>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TAbstractResource.SetCustomRawDataStream">
+<short>Sets a custom stream as the underlying stream for RawData</short>
+<descr>
+<p>Normally, <link id="TAbstractResource.RawData">RawData</link> uses a memory stream or the original resource stream (e.g. the original file containing the resource) as its underlying stream. This method allows the user to use a custom stream as the underlying stream. This can be useful when a resource must be created from the contents of an original file as-is.</p>
+<p>If <var>aStream</var> is <var>nil</var>, a new memory stream is used as the underlying stream. This can be used to remove a previously set custom stream as the underlying stream.</p>
+<p><b>Sample code</b></p>
+<p>This code creates a resource containing an html file</p>
+<code>
+var
+  aType, aName : TResourceDesc;
+  aRes : TGenericResource;
+  aFile : TFileStream;
+begin
+  aType:=TResourceDesc.Create(RT_HTML);
+  aName:=TResourceDesc.Create('index');
+  aRes:=TGenericResource.Create(aType,aName);
+  aFile:=TFileStream.Create('index.html',fmOpenRead or fmShareDenyNone);
+  aRes.SetCustomRawDataStream(aFile);
+
+  //do something...
+
+  aRes.Free;
+  aFile.Free;
+  aType.Free;
+  aName.Free;
+end;
+</code>
+</descr>
+<seealso>
+<link id="TAbstractResource.RawData"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResource.SetCustomRawDataStream.aStream">
+<short>The custom stream to use as the underlying <link id="TAbstractResource.RawData">RawData</link> stream. It can be <var>nil</var></short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource._Type">
+<short>The type of the resource</short>
+<descr>
+<remark>
+<p>Please note that some <link id="TAbstractResource"/> descendants don't allow resource type to be changed (e.g: it's not possible for a <link id="bitmapresource.TBitmapResource">TBitmapResource</link> to have a type other than <link id="RT_BITMAP"/>). If it is the case, an <link id="EResourceDescChangeNotAllowedException"/> exception is raised.</p>
+<p>Moreover, if the resource is contained in a <link id="TResources"/> object, type change is not allowed.</p>
+</remark>
+</descr>
+<seealso>
+<link id="TAbstractResource.ChangeDescTypeAllowed"/>
+<link id="TAbstractResource.ChangeDescValueAllowed"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.Name">
+<short>The name of the resource</short>
+<descr>
+<remark>
+<p>Please note that some <link id="TAbstractResource"/> descendants don't allow resource name to be changed (e.g: a <link id="stringtableresource.TStringTableResource">TStringTableResource</link> name is determined by the range of strings' ID it contains). If it is the case, an <link id="EResourceDescChangeNotAllowedException"/> exception is raised.</p>
+<p>Moreover, if the resource is contained in a <link id="TResources"/> object, name change is not allowed.</p>
+</remark>
+</descr>
+<seealso>
+<link id="TAbstractResource.ChangeDescTypeAllowed"/>
+<link id="TAbstractResource.ChangeDescValueAllowed"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.LangID">
+<short>The language ID of the resource</short>
+<descr>
+<remark>Please note that if the resource is contained in a <link id="TResources"/> object, language ID change is not allowed: trying to do so results in an <link id="EResourceLangIDChangeNotAllowedException"/> exception being raised.</remark>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.DataSize">
+<short>The size of resource raw data</short>
+<descr>
+<p>DataSize is the length, in bytes, of the resource data, accessible via <link id="TAbstractResource.RawData">RawData</link> property.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource.RawData"/>
+<link id="TAbstractResource.DataOffset"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.HeaderSize">
+<short>The size of resource header</short>
+<descr>
+<p>This property is not always meaningful, since not all file formats support it.</p>
+<p>Its value, when nonzero, can be used for information purposes.</p>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.DataVersion">
+<short>The version of the resource data</short>
+<descr>
+<p>This property is not always meaningful, since not all file formats support it.</p>
+<p>Its value, when nonzero, can be used for information purposes.</p>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.MemoryFlags">
+<short>The memory flags of the resource</short>
+<descr>
+<p>This field is a combination of the following flags</p>
+<ul>
+<li><link id="MF_MOVEABLE"/></li>
+<li><link id="MF_PURE"/></li>
+<li><link id="MF_PRELOAD"/></li>
+<li><link id="MF_DISCARDABLE"/></li>
+</ul>
+<p>By default, a newly created resource has <link id="MF_MOVEABLE"/> and <link id="MF_DISCARDABLE"/> flags set.</p>
+<remark>Please note that memory flags are ignored by Windows and Free Pascal RTL. They are provided only for compatibility with 16-bit Windows.</remark>
+<p>This property is not always meaningful, since not all file formats support it.</p>
+<p>Its value, when nonzero, can be used for information purposes.</p>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.Version">
+<short>A user defined version number</short>
+<descr>
+<p>A tool that writes resource files can write version information in this field.</p>
+<p>This property is not always meaningful, since not all file formats support it.</p>
+<p>Its value, when nonzero, can be used for information purposes.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource.Characteristics"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.Characteristics">
+<short>A user defined piece of data</short>
+<descr>
+<p>A tool that writes resource files can write arbitrary data in this field.</p>
+<p>This property is not always meaningful, since not all file formats support it.</p>
+<p>Its value, when nonzero, can be used for information purposes.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource.Version"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.DataOffset">
+<short>The offset of resource data from the beginning of the stream</short>
+<descr>
+<p>A reader sets this property to let the resource know where its raw data begins in the resource stream.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource.RawData"/>
+<link id="TAbstractResource.DataSize"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.CodePage">
+<short>The code page of the resource</short>
+<descr>
+<p>This property is not always meaningful, since not all file formats support it.</p>
+<p>Its value, when nonzero, can be used for information purposes.</p>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.RawData">
+<short>The raw resource data stream</short>
+<descr>
+<p>This property provides access to the resource raw data in a stream-like way.</p>
+<p>When a resource has been read from a stream, RawData redirects read operations to the original stream. When RawData is written to, a copy-on-write mechanism copies data from the original stream to a memory stream.</p>
+<p>The copy-on-write behaviour can be controlled via <link id="TAbstractResource.CacheData">CacheData</link> property.</p>
+<p>Note that for some predefined resource types there are better ways to read and write resource data: some resource types use specific formats, so RawData might not always be what one expected. E.g. in a resource of type <link id="RT_BITMAP"/>, RawData doesn't contain a valid BMP file: in this case it's better to use <link id="bitmapresource.TBitmapResource.BitmapData">BitmapData</link> stream of <link id="bitmapresource.TBitmapResource">TBitmapResource</link> class to work with a BMP-like stream.</p>
+<remark>When writing to a "specialized" stream in a descendant class (like the <link id="bitmapresource.TBitmapResource.BitmapData">TBitmapResource.BitmapData</link> stream mentioned earlier), RawData contents might not be valid anymore. If you need to access RawData again, be sure to call <link id="TAbstractResource.UpdateRawData">UpdateRawData</link> method first.</remark>
+<p>Usually there isn't much penalty in using specialized streams in descendant classes, since data isn't duplicated in two or more streams, whenever possible. So, having a very large bitmap resource and reading/writing it via <link id="bitmapresource.TBitmapResource.BitmapData">TBitmapResource.BitmapData</link> doesn't mean the bitmap is allocated two times.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource.CacheData"/>
+<link id="TAbstractResource.UpdateRawData"/>
+<link id="TAbstractResource.SetCustomRawDataStream"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.CacheData">
+<short>Controls the copy-on-write behaviour of the resource</short>
+<descr>
+<p>When CacheData is true, copy-on-write mechanism of <link id="TAbstractResource.RawData">RawData</link> is enabled.</p>
+<p>Setting CacheData to false forces the raw resource data to be loaded in memory without performing any caching.</p>
+<p>By default, CacheData is true.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource.RawData"/>
+<link id="TResources.CacheData"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.OwnerList">
+<short>The resource list that owns this resource</short>
+<descr>
+<p>This property identifies the <link id="TResources"/> object to which this resource belongs to.</p>
+<p>This property can be <var>nil</var> if the resource isn't part of a resource list.</p>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResource.Owner">
+<short>The owner of this resource</short>
+<descr>
+<p>This property is meaningful only for those sub-resources that are part of a larger <i>group resource</i>.</p>
+<p><b>Example</b>: an icon is made by a <link id="RT_GROUP_ICON"/> resource and many <link id="RT_ICON"/> resources that hold single-image data. Each <link id="RT_ICON"/> resource has a pointer to the <link id="RT_GROUP_ICON"/> resource in its Owner property.</p>
+</descr>
+</element>
+
+<!-- "class of" type Visibility: default -->
+<element name="TResourceClass">
+<short>Resource metaclass</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TGenericResource">
+<short>Generic resource class</short>
+<descr>
+<p>This class represents a generic resource.</p>
+<p>It is suitable to use in all situations where a higher level class is not needed (e.g. the resource raw data is made of arbitrary data) or when total low-level control is desirable.</p>
+<p>This class is also the default one that is used by <link id="resfactory.TResourceFactory">TResourceFactory</link> when it finds no class matching the given type.</p>
+</descr>
+<seealso>
+<link id="resfactory.TResourceFactory.CreateResource">TResourceFactory.CreateResource</link>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TAbstractResourceReader">
+<short>Base abstract resource reader class</short>
+<descr>
+<p>This is the base class that represents a resource reader.</p>
+<p>A resource reader is an object whose job is to populate a <link id="TResources"/> object with resources read from a stream in a specific format.</p>
+<p>Typically, a <link id="TResources"/> object invokes <link id="TAbstractResourceReader.CheckMagic">CheckMagic</link> method of the resource reader when it's searching for a reader able to read a certain stream, and <link id="TAbstractResourceReader.Load">Load</link> method when it wants the reader to read data from the stream.</p>
+<p>Usually each resource reader registers itself with <link id="TResources"/> class in the <var>initialization</var> section of the unit in which it is implemented: this way a <link id="TResources"/> object can find it when probing a stream that is to be read.</p>
+<remark>An object of this class should never be directly instantiated: use a descendant class instead.</remark>
+</descr>
+<seealso>
+<link id="TResources"/>
+<link id="TAbstractResource"/>
+<link id="TAbstractResourceWriter"/>
+<link id="resreader.TResResourceReader">TResResourceReader</link>
+<link id="coffreader.TCoffResourceReader">TCoffResourceReader</link>
+<link id="winpeimagereader.TWinPEImageResourceReader">TWinPEResourceReader</link>
+<link id="elfreader.TElfResourceReader">TElfResourceReader</link>
+<link id="externalreader.TExternalResourceReader">TExternalResourceReader</link>
+<link id="dfmreader.TDfmResourceReader">TDfmResourceReader</link>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TAbstractResourceWriter">
+<short>Base abstract resource writer class</short>
+<descr>
+<p>This is the base class that represents a resource writer.</p>
+<p>A resource writer is an object whose job is to write all resources contained in a <link id="TResources"/> object to a stream in a specific format.</p>
+<p>Typically, a <link id="TResources"/> object invokes <link id="TAbstractResourceWriter.Write">Write</link> method of the resource writer when it wants the writer to write data to a stream.</p>
+<p>Usually each resource writer registers itself with <link id="TResources"/> class in the <var>initialization</var> section of the unit in which it is implemented: this way a <link id="TResources"/> object can find it when it is asked to write itself to a file, and no writer was specified (the writer is found based on the extension of the file to write to).</p>
+<remark>An object of this class should never be directly instantiated: use a descendant class instead.</remark>
+</descr>
+<seealso>
+<link id="TResources"/>
+<link id="TAbstractResource"/>
+<link id="TAbstractResourceReader"/>
+<link id="reswriter.TResResourceWriter">TResResourceWriter</link>
+<link id="coffwriter.TCoffResourceWriter">TCoffResourceWriter</link>
+<link id="elfwriter.TElfResourceWriter">TElfResourceWriter</link>
+<link id="externalwriter.TExternalResourceWriter">TExternalResourceWriter</link>
+</seealso>
+</element>
+
+<!-- "class of" type Visibility: default -->
+<element name="TResourceReaderClass">
+<short>Resource reader metaclass</short>
+</element>
+
+<!-- "class of" type Visibility: default -->
+<element name="TResourceWriterClass">
+<short>Resource writer metaclass</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResources.Find">
+<short>Searches for a resource</short>
+<descr>
+<p>This method searches for a resource with the given type and name. If a language ID is not provided, the first resource found that matches <var>aType</var> and <var>aName</var> is returned.</p>
+</descr>
+<errors>
+<p>If the resource is not found, an <link id="EResourceNotFoundException"/> exception is raised.</p>
+</errors>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResources.Find.Result">
+<short>The resource that matches the search criteria</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Find.aType">
+<short>The type of the resource to search for</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Find.aName">
+<short>The name of the resource to search for</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Find.aLangID">
+<short>The language ID of the resource to search for</short>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TResources.Create">
+<short>Creates a new TResources object</short>
+</element>
+
+<!-- destructor Visibility: public -->
+<element name="TResources.Destroy">
+<short>Destroys the object</short>
+<descr>
+<remark>All resources are destroyed as well.</remark>
+</descr>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.Add">
+<short>Adds a resource</short>
+<descr>
+<p>This method adds <var>aResource</var> to the object, and sets itself as the owner list of the resource.</p>
+</descr>
+<errors>
+<p>If a resource with the same type, name and language ID already exists, an <link id="EResourceDuplicateException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TResources.AddAutoID"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Add.aResource">
+<short>The resource to add</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResources.AddAutoID">
+<short>Adds a resource and gives it a new autogenerated name</short>
+<descr>
+<p>This method tries to find a spare ID to use as a name for the given resource, assigns it to the resource, and adds it.</p>
+<p>This method is useful when the name of the resource is not important. E.g. a group resource doesn't care about the names of its sub-resources, so it could use this method to ensure that its sub-resources don't clash with names of other sub-resources of the same type.</p>
+</descr>
+<errors>
+<p>If there are no more free IDs for the resource type of the given resource (that is, when the number of resources of the same type of <var>aResource</var> with an ID name is equal to 65536) an <link id="ENoMoreFreeIDsException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TResources.Add"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResources.AddAutoID.Result">
+<short>The autogenerated ID of the added resource</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.AddAutoID.aResource">
+<short>The resource to add</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.Clear">
+<short>Deletes all resources</short>
+<descr>
+<p>This method empties the TResources object destroying all resources.</p>
+</descr>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResources.FindReader">
+<short>Searches for a suitable resource reader</short>
+<descr>
+<p>This method tries to find a resource reader able to read the stream passed as parameter.</p>
+<p>If an extension is specified, only readers matching that extension are tried. The extension is case-insensitive and includes the leading dot, unless the empty string is passed (which means "no extension", e.g. a unix executable, which doesn't have an extension).</p>
+<p>If a suitable reader is found, an instance of that reader is returned.</p>
+<remark>To make a resource reader class known, add that resource reader unit to the uses clause of your program.</remark>
+</descr>
+<errors>
+<p>If no suitable reader is found, an <link id="EResourceReaderNotFoundException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TAbstractResourceReader"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResources.FindReader.Result">
+<short>An instance of a <link id="TAbstractResourceReader"/> descendant.</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.FindReader.aStream">
+<short>The stream to be probed</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.FindReader.aExtension">
+<short>The extension the reader is registered for</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.MoveFrom">
+<short>Moves all resources of another TResources object to itself</short>
+<descr>
+<p>This method takes all resources from object <var>aResources</var> and adds them to this object. <var>aResources</var> object is left empty.</p>
+</descr>
+<errors>
+<p>If a resource with the same type, name and language ID already exists, an <link id="EResourceDuplicateException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TResources.Add"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.MoveFrom.aResources">
+<short>The TResources object from which resources must be taken</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResources.Remove">
+<short>Removes a resource</short>
+<descr>
+<p>This method searches for a resource based on passed parameters and removes it from the object.</p>
+<p>The removed resource is then returned.</p>
+</descr>
+<errors>
+<p>If no matching resource is found, an <link id="EResourceNotFoundException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TResources.Find"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResources.Remove.Result">
+<short>The removed resource</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Remove.aType">
+<short>The type of the resource to search for</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Remove.aName">
+<short>The name of the resource to search for</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Remove.aLangID">
+<short>The language ID of the resource to search for</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Remove.aResource">
+<short>The resource to remove</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Remove.aIndex">
+<short>The index of the resource to remove</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.LoadFromStream">
+<short>Loads the contents of the object from a stream</short>
+<descr>
+<p>This method clears the TResources object and loads its contents from the stream passed as parameter.</p>
+<p>If a reader is specified, that reader is used. Otherwise, the stream is probed to find a suitable reader.</p>
+<remark>If <link id="TResources.CacheData">CacheData</link> is set to <var>true</var>, the stream will be used as the underlying stream of each resource <link id="TAbstractResource.RawData">RawData</link> stream. This means that the stream must not be freed until all resources in the TResources object are freed: this happens when the TResources object is cleared or is loaded again from a different source. If you need to free the stream while there are still resources, disable the copy-on-write mechanism by setting <link id="TResources.CacheData">CacheData</link> property to <var>false</var>.</remark>
+</descr>
+<errors>
+<p>If no reader is passed and probing fails, an <link id="EResourceReaderNotFoundException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TAbstractResourceReader"/>
+<link id="TAbstractResource.RawData"/>
+<link id="TAbstractResource.CacheData"/>
+<link id="TResources.CacheData"/>
+<link id="TResources.LoadFromFile"/>
+<link id="TResources.Clear"/>
+<link id="TResources.FindReader"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.LoadFromStream.aStream">
+<short>The stream to read from</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.LoadFromStream.aReader">
+<short>The resource reader to use to read the stream</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.LoadFromFile">
+<short>Loads the contents of the object from a file</short>
+<descr>
+<p>This method clears the TResources object and loads its contents from the file passed as parameter.</p>
+<p>If a reader is specified, that reader is used. Otherwise, the file is probed to find a suitable reader.</p>
+<remark>If <link id="TResources.CacheData">CacheData</link> is set to <var>true</var>, the file will be left open and used as the underlying stream of each resource <link id="TAbstractResource.RawData">RawData</link> stream. This means that the file will be open until the TResources object is cleared or is loaded again from a different source. If you want the file to be closed while there are still resources, disable the copy-on-write mechanism by setting <link id="TResources.CacheData">CacheData</link> property to <var>false</var>.</remark>
+<p><b>Sample code</b></p>
+<p>This code extracts resources from an exe file</p>
+<code>
+var
+  resources : TResources;
+begin
+  resources:=TResources.Create;
+  resources.LoadFromFile('myexe.exe');
+  resources.WriteToFile('myexe.res');
+  resources.Free;
+end;
+</code>
+</descr>
+<errors>
+<p>If no reader is passed and probing fails, an <link id="EResourceReaderNotFoundException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TAbstractResourceReader"/>
+<link id="TAbstractResource.RawData"/>
+<link id="TAbstractResource.CacheData"/>
+<link id="TResources.CacheData"/>
+<link id="TResources.LoadFromStream"/>
+<link id="TResources.Clear"/>
+<link id="TResources.FindReader"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.LoadFromFile.aFileName">
+<short>The name of file to read from</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.LoadFromFile.aReader">
+<short>The reader to use to read the file</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.RegisterReader">
+<short>Registers a resource reader class</short>
+<descr>
+<p>This class method registers a resource reader class.</p>
+<p>When registered, a class is known to TResources class, and can be used by <link id="TResources.FindReader">FindReader</link>, <link id="TResources.LoadFromStream">LoadFromStream</link> and <link id="TResources.LoadFromFile">LoadFromFile</link> methods when probing.</p>
+<p>Usually this method is called in the <var>initialization</var> section of the unit implementing a <link id="TAbstractResourceReader"/> descendant.</p>
+<p>A class can be registered multiple times, one for each extension it is able to read. Multiple class can be registered for the same extension (e.g. both a coff and a elf reader can be registered for the .o extension). The extension must include the leading dot unless the empty string is used (which means "no extension", e.g. a unix executable, which doesn't have an extension).</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader"/>
+<link id="TResources.FindReader"/>
+<link id="TResources.LoadFromStream"/>
+<link id="TResources.LoadFromFile"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.RegisterReader.aExtension">
+<short>The extension for which the class must be registered</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.RegisterReader.aClass">
+<short>The <link id="TAbstractResourceReader"/> descendant to register</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.RegisterWriter">
+<short>Registers a resource writer class</short>
+<descr>
+<p>This class method registers a resource writer class.</p>
+<p>When registered, a class is known to TResources class, and can be used by <link id="TResources.WriteToFile">WriteToFile</link> method when probing.</p>
+<p>Usually this method is called in the <var>initialization</var> section of the unit implementing a <link id="TAbstractResourceWriter"/> descendant.</p>
+<p>A class can be registered multiple times, one for each extension it is able to write. Multiple class can be registered for the same extension (e.g. both a coff and a elf writer can be registered for the .o extension) although only the first one found will be used when probing. The extension must include the leading dot unless the empty string is used (which means "no extension", e.g. a unix executable, which doesn't have an extension).</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceWriter"/>
+<link id="TResources.WriteToFile"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.RegisterWriter.aExtension">
+<short>The extension for which the class must be registered</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.RegisterWriter.aClass">
+<short>The <link id="TAbstractResourceWriter"/> descendant to register</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.WriteToStream">
+<short>Writes the contents of the object to a stream</short>
+<descr>
+<p>This method writes the contents of the object to a stream via the specified <link id="TAbstractResourceWriter"/> descendant</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceWriter"/>
+<link id="TResources.WriteToFile"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.WriteToStream.aStream">
+<short>The stream to write to</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.WriteToStream.aWriter">
+<short>The resource writer to use to write the stream</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResources.WriteToFile">
+<short>Writes the contents of the object to a file</short>
+<descr>
+<p>This method writes the contents of the object to a file whose name is passed as parameter.</p>
+<p>If a writer is specified, that writer is used. Otherwise, the first registered writer matching the file name extension is used.</p>
+</descr>
+<errors>
+<p>If no writer is passed and no suitable writer is found, an <link id="EResourceWriterNotFoundException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TAbstractResourceWriter"/>
+<link id="TResources.WriteToStream"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.WriteToFile.aFileName">
+<short>The name of the file to write to</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.WriteToFile.aWriter">
+<short>The resource writer to use to write to the file</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResources.Count">
+<short>The number of resources in the object</short>
+<seealso>
+<link id="TResources.Items"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResources.Items">
+<short>Indexed array of resources in the object</short>
+<descr>
+<p>This property can be used to access all resources in the object.</p>
+<remark>This array is 0-based: valid elements range from 0 to <link id="TResources.Count">Count</link>-1.</remark>
+</descr>
+<seealso>
+<link id="TResources.Count"/>
+<link id="TAbstractResource"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResources.Items.Index">
+<short>The index of the resource to access</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResources.CacheData">
+<short>Controls the copy-on-write behaviour of all resources</short>
+<descr>
+<p>Changing this property changes <link id="TAbstractResource.CacheData">CacheData</link> property of all resources contained in the object.</p>
+<p>This property affects existing resources and resources that are added or loaded.</p>
+<p>By default, CacheData is true.</p>
+</descr>
+<seealso>
+<link id="TAbstractResource.CacheData"/>
+<link id="TAbstractResource.RawData"/>
+</seealso>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceReader.SetDataSize">
+<short>Protected method to let a reader set a resource <link id="TAbstractResource.DataSize">DataSize</link> property</short>
+<descr>
+<p>This method allows a descendant class to set <link id="TAbstractResource.DataSize">DataSize</link> property of a resource that is being loaded.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.SetHeaderSize"/>
+<link id="TAbstractResourceReader.SetDataOffset"/>
+<link id="TAbstractResourceReader.SetRawData"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.SetDataSize.aResource">
+<short>The resource whose <link id="TAbstractResource.DataSize">DataSize</link> property must be set</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.SetDataSize.aValue">
+<short>The value to set the property to</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceReader.SetHeaderSize">
+<short>Protected method to let a reader set a resource <link id="TAbstractResource.HeaderSize">HeaderSize</link> property</short>
+<descr>
+<p>This method allows a descendant class to set <link id="TAbstractResource.HeaderSize">HeaderSize</link> property of a resource that is being loaded.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.SetDataSize"/>
+<link id="TAbstractResourceReader.SetDataOffset"/>
+<link id="TAbstractResourceReader.SetRawData"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.SetHeaderSize.aResource">
+<short>The resource whose <link id="TAbstractResource.HeaderSize">HeaderSize</link> property must be set</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.SetHeaderSize.aValue">
+<short>The value to set the property to</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceReader.SetDataOffset">
+<short>Protected method to let a reader set a resource <link id="TAbstractResource.DataOffset">DataOffset</link> property</short>
+<descr>
+<p>This method allows a descendant class to set <link id="TAbstractResource.DataOffset">DataOffset</link> property of a resource that is being loaded.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.SetDataSize"/>
+<link id="TAbstractResourceReader.SetHeaderSize"/>
+<link id="TAbstractResourceReader.SetRawData"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.SetDataOffset.aResource">
+<short>The resource whose <link id="TAbstractResource.DataOffset">DataOffset</link> property must be set</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.SetDataOffset.aValue">
+<short>The value to set the property to</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceReader.SetRawData">
+<short>Protected method to let a reader set a resource <link id="TAbstractResource.RawData">RawData</link> property</short>
+<descr>
+<p>This method allows a descendant class to set <link id="TAbstractResource.RawData">RawData</link> property of a resource that is being loaded.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.SetDataSize"/>
+<link id="TAbstractResourceReader.SetHeaderSize"/>
+<link id="TAbstractResourceReader.SetDataOffset"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.SetRawData.aResource">
+<short>The resource whose <link id="TAbstractResource.RawData">RawData</link> property must be set</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.SetRawData.aStream">
+<short>The value to set the property to</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceReader.CallSubReaderLoad">
+<short>Calls another reader's <link id="TAbstractResourceReader.Load">Load</link> method</short>
+<descr>
+<p>This method allows a descendant class to call another reader's <link id="TAbstractResourceReader.Load">Load</link> method. This can be useful when a reader needs to use another one.</p>
+</descr>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.CallSubReaderLoad.aReader">
+<short>The reader whose <link id="TAbstractResourceReader.Load">Load</link> method must be called</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.CallSubReaderLoad.aResources">
+<short>The <var>aResources</var> parameter of <link id="TAbstractResourceReader.Load">Load</link> method</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.CallSubReaderLoad.aStream">
+<short>The <var>aStream</var> parameter of <link id="TAbstractResourceReader.Load">Load</link> method</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceReader.AddNoTree">
+<short>Adds a resource without updating the internal tree</short>
+<descr>
+<p>This protected method is used by descendents of <link id="TAbstractResourceReader"/> after they add new resources to the internal resource tree used by a <link id="TResources"/> object. Calling this method notifies the <link id="TResources"/> object about the newly-added resource.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.GetTree"/>
+<link id="resourcetree.TRootResTreeNode">TRootResTreeNode</link>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.AddNoTree.aResources">
+<short>The TResources object to be notified</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.AddNoTree.aResource">
+<short>The resource that has been added to the tree</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceReader.GetTree">
+<short>Gets the internal resource tree of a TResources object</short>
+<descr>
+<p>This protected method can be used by descendents of <link id="TAbstractResourceReader"/> to obtain the internal resource tree used by a <link id="TResources"/> object. The internal resource tree is an instance of <link id="resourcetree.TRootResTreeNode">TRootResTreeNode</link>.</p>
+<p>Some resource readers can improve their performance if, instead of calling <link id="TResources.Add"/>, add themselves resources to the internal tree used by a <link id="TResources"/> object.</p>
+<remark>After adding a resource to a resource tree, a reader must always call <link id="TAbstractResourceReader.AddNoTree">AddNoTree</link> method to let the <link id="TResources"/> object know about the newly-added resource.</remark>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.AddNoTree"/>
+<link id="resourcetree.TRootResTreeNode">TRootResTreeNode</link>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.GetTree.aResources">
+<short>The <link id="TResources"/> object whose tree must be returned</short>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResourceReader.GetTree.Result">
+<short>The resource tree. It is an instance of <var>TRootResTreeNode</var>.</short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResourceReader.GetExtensions">
+<short>Returns the extensions the reader is registered for</short>
+<descr>
+<p>Descendant classes must implement this method to provide access to <link id="TAbstractResourceReader.Extensions">Extensions</link> property.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.Extensions"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResourceReader.GetExtensions.Result">
+<short>The extensions the reader is registered for</short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResourceReader.GetDescription">
+<short>Returns the description of the reader</short>
+<descr>
+<p>Descendant classes must implement this method to provide access to <link id="TAbstractResourceReader.Description">Description</link> property.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.Description"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResourceReader.GetDescription.Result">
+<short>The description of the reader</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceReader.Load">
+<short>Loads resources from a stream</short>
+<descr>
+<p>A <link id="TResources"/> object invokes this method when it needs to be loaded from a stream, passing itself as the <var>aResources</var> parameter and the stream as the <var>aStream</var> parameter.</p>
+<p><var>aStream</var> position is already correctly set: the reader must start to read from there.</p>
+<p>Descendant classes must ensure that the the stream is in a format they recognize, otherwise an <link id="EResourceReaderWrongFormatException"/> exception must be raised.</p>
+<p>Each resource is then created, read from the stream and added to the <link id="TResources"/> object.</p>
+<p>When reading a resource, a reader must:</p>
+<ul>
+<li>Create the resource via <link id="resfactory.TResourceFactory.CreateResource">TResourceFactory.CreateResource</link> class method with the correct type and name.</li>
+<li><p>Set at least the following resource properties:</p>
+<ul>
+<li><link id="TAbstractResource.DataSize">DataSize</link>, via <link id="TAbstractResourceReader.SetDataSize">SetDataSize</link> method.</li>
+<li><link id="TAbstractResource.DataOffset">DataOffset</link>, via <link id="TAbstractResourceReader.SetDataOffset">SetDataSize</link> method. This is the offset of the resource data from the beginning of the stream.</li>
+<li><link id="TAbstractResource.RawData">RawData</link>. The reader must create a <link id="resdatastream.TResourceDataStream">TResourceDataStream</link> object and assign it to the resource via <link id="TAbstractResourceReader.SetRawData">SetRawData</link> method.</li>
+</ul>
+</li>
+</ul>
+</descr>
+<errors>
+<p>If the stream is in a format not recognized by the reader, a <link id="EResourceReaderWrongFormatException"/> exception must be raised.</p>
+<p>If the stream ends prematurely, a <link id="EResourceReaderUnexpectedEndOfStreamException"/> exception must be raised.</p>
+</errors>
+<seealso>
+<link id="TResources"/>
+<link id="TResources.LoadFromStream"/>
+<link id="TResources.LoadFromFile"/>
+<link id="TAbstractResource"/>
+<link id="TAbstractResource.DataSize"/>
+<link id="TAbstractResource.DataOffset"/>
+<link id="TAbstractResource.RawData"/>
+<link id="TAbstractResourceReader.SetDataSize"/>
+<link id="TAbstractResourceReader.SetDataOffset"/>
+<link id="TAbstractResourceReader.SetRawData"/>
+<link id="TAbstractResourceReader.CheckMagic"/>
+<link id="resdatastream.TResourceDataStream">TResourceDataStream</link>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.Load.aResources">
+<short>The <link id="TResources"/> object to be loaded from the stream</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.Load.aStream">
+<short>The stream which resources must be loaded from </short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResourceReader.CheckMagic">
+<short>Checks whether a stream is in a format the reader recognizes</short>
+<descr>
+<p>A <link id="TResources"/> object invokes this method when it is searching for a reader able to read a stream, passing that stream as the <var>aStream</var> parameter.</p>
+<p><var>aStream</var> position is already correctly set: the reader must start to read from there.</p>
+<p>This method should read the minimum amount of information needed to recognize the contents of a stream as a valid format: it usually means reading a magic number or a file header.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceReader.Load"/>
+<link id="TResources.FindReader"/>
+<link id="TResources.LoadFromStream"/>
+<link id="TResources.LoadFromFile"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResourceReader.CheckMagic.Result">
+<short><var>true</var> if the format of the stream is recognized</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceReader.CheckMagic.aStream">
+<short>The stream to check</short>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TAbstractResourceReader.Create">
+<short>Creates a new reader object</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResourceReader.Extensions">
+<short>The extensions of file types the reader is able to read</short>
+<descr>
+<p>This property is a string made of space-separated file extensions (each including the leading dot), all lowercase.</p>
+<p>This property signals which file types the reader is able to read.</p>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResourceReader.Description">
+<short>The reader description</short>
+<descr>
+<p>This property provides a textual description of the reader, e.g. "FOO resource reader"</p>
+</descr>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceWriter.GetTree">
+<short>Gets the internal resource tree of a TResources object</short>
+<descr>
+<p>This protected method can be used by descendents of <link id="TAbstractResourceWriter"/> to obtain the internal resource tree used by a <link id="TResources"/> object. The internal resource tree is an instance of <link id="resourcetree.TRootResTreeNode">TRootResTreeNode</link>.</p>
+<p>Some resource writers need to order resources with a tree structure before writing them to a file. Instead of doing this work themselves, they can use the already-ordered internal resource tree of the <link id="TResources"/> object they must write.</p>
+</descr>
+<seealso>
+<link id="resourcetree.TRootResTreeNode">TRootResTreeNode</link>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceWriter.GetTree.aResources">
+<short>The <link id="TResources"/> object whose tree must be returned</short>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResourceWriter.GetTree.Result">
+<short>The resource tree. It is an instance of <var>TRootResTreeNode</var>.</short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResourceWriter.GetExtensions">
+<short>Returns the extensions the writer is registered for</short>
+<descr>
+<p>Descendant classes must implement this method to provide access to <link id="TAbstractResourceWriter.Extensions">Extensions</link> property.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceWriter.Extensions"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResourceWriter.GetExtensions.Result">
+<short>The extensions the writer is registered for</short>
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TAbstractResourceWriter.GetDescription">
+<short>Returns the description of the writer</short>
+<descr>
+<p>Descendant classes must implement this method to provide access to <link id="TAbstractResourceWriter.Description">Description</link> property.</p>
+</descr>
+<seealso>
+<link id="TAbstractResourceWriter.Description"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TAbstractResourceWriter.GetDescription.Result">
+<short>The description of the writer</short>
+</element>
+
+<!-- procedure Visibility: protected -->
+<element name="TAbstractResourceWriter.Write">
+<short>Writes resources to a stream</short>
+<descr>
+<p>A <link id="TResources"/> object invokes this method when it needs to be written to a stream, passing itself as the <var>aResources</var> parameter and the stream as the <var>aStream</var> parameter.</p>
+<p><var>aStream</var> position is already correctly set: the writer must start to write from there.</p>
+<p>A writer must write data in the way specified by the format it supports: usually this means writing a header and all resources contained in the <link id="TResources"/> object.</p>
+<p>For each resource, a writer should write some information about the resource (like type and name) in a way defined by the format it implements, and the resource data, which is accessible by <link id="TAbstractResource.RawData">RawData</link> property of the resource.</p>
+</descr>
+<seealso>
+<link id="TResources"/>
+<link id="TResources.WriteToStream"/>
+<link id="TResources.WriteToFile"/>
+<link id="TAbstractResource"/>
+<link id="TAbstractResource.DataSize"/>
+<link id="TAbstractResource.RawData"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceWriter.Write.aResources">
+<short>The <link id="TResources"/> object to be written to the stream</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TAbstractResourceWriter.Write.aStream">
+<short>The stream which resources must be written to</short>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TAbstractResourceWriter.Create">
+<short>Creates a new writer object</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResourceWriter.Extensions">
+<short>The extensions of file types the writer is able to write</short>
+<descr>
+<p>This property is a string made of space-separated file extensions (each including the leading dot), all lowercase.</p>
+<p>This property signals which file types the writer is able to write.</p>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TAbstractResourceWriter.Description">
+<short>The writer description</short>
+<descr>
+<p>This property provides a textual description of the writer, e.g. "FOO resource writer"</p>
+</descr>
+</element>
+
+</module> <!-- resource -->
+
+</package>
+</fpdoc-descriptions>

+ 480 - 0
packages/fcl-res/xml/resourcetree.xml

@@ -0,0 +1,480 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    resourcetree
+  ====================================================================
+-->
+
+<module name="resourcetree">
+<short>Implements an ordered tree of resources</short>
+<descr>
+<p>This unit implements classes that represent an ordered tree of resources.</p>
+<p>Such a tree is used internally by <link id="resource.TResources">TResources</link> to speed up operations, and by certain resource readers and writers that deal with resource formats where data is stored as ordered trees of resources. For this reason, only implementors of resource readers and writers should be interested in these classes.</p>
+<p>A tree begins with a root node, which is an instance of <link id="TRootResTreeNode"/>. The root node contains type nodes, that contain name nodes, that contain language id nodes. Finally, a language id node contains a resource.</p>
+<p>Each node contains its sub nodes in two lists: a Named list for nodes identified by a name (a string), and an ID list for nodes identified by an ID (an integer). In each list, nodes are sorted in ascending order.</p>
+<p>Many resource formats (PECOFF, ELF, Mach-O, and external resource files) use this exact format to store resource information.</p>
+<remark>When a tree is destroyed, the resources it references aren't destroyed.</remark>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TResourceTreeNode">
+<short>Abstract class representing a resource tree node.</short>
+<descr>
+<p>This class represents a node in a resource tree.</p>
+<remark>An object of this class should never be directly instantiated. To create a node, call <link id ="TResourceTreeNode.CreateSubNode">CreateSubNode</link> method of an already existing node.</remark>
+</descr>
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TResourceTreeNode.fParent">
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TResourceTreeNode.fNamedEntries">
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TResourceTreeNode.fIDEntries">
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TResourceTreeNode.fSubDirRVA">
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TResourceTreeNode.fDataRVA">
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TResourceTreeNode.fNameRva">
+</element>
+
+<!-- variable Visibility: protected -->
+<element name="TResourceTreeNode.fDesc">
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TResourceTreeNode.GetNamedCount">
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.GetNamedCount.Result">
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TResourceTreeNode.GetNamedEntry">
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.GetNamedEntry.Result">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.GetNamedEntry.index">
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TResourceTreeNode.GetIDCount">
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.GetIDCount.Result">
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TResourceTreeNode.GetIDEntry">
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.GetIDEntry.Result">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.GetIDEntry.index">
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TResourceTreeNode.GetData">
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.GetData.Result">
+</element>
+
+<!-- function Visibility: protected -->
+<element name="TResourceTreeNode.Find">
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.Find.Result">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.aList">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.aDesc">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.index">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.aLangID">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.aType">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.aName">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.noLangID">
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.toDelete">
+</element>
+
+<!-- constructor Visibility: protected -->
+<element name="TResourceTreeNode.Create">
+</element>
+
+<!-- property Visibility: protected -->
+<element name="TResourceTreeNode.Parent">
+</element>
+
+<!-- destructor Visibility: public -->
+<element name="TResourceTreeNode.Destroy">
+<short>Destroys the object.</short>
+<descr>
+<remark>Only root nodes (instances of <link id="TRootResTreeNode"/>) should be destroyed. Children nodes are destroyed by their parent when needed.</remark>
+</descr>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResourceTreeNode.Add">
+<short>Adds a new resource to the tree</short>
+<descr>
+<p>This method adds a new resource to the tree, creating all needed sub nodes</p>
+<remark>This method should only be called on root nodes (instances of <link id="TRootResTreeNode"/>).</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.Remove"/>
+</seealso>
+<errors>
+<p>If a resource with the same type, name and language ID already exists, an <link id="resource.EResourceDuplicateException">EResourceDuplicateException</link> exception is raised.</p>
+</errors>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Add.aResource">
+<short>The resource to add</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceTreeNode.CreateSubNode">
+<short>Creates a subnode</short>
+<descr>
+<p>This method creates a subnode, identified by the given resource description.</p>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.Desc"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.CreateSubNode.Result">
+<short>The newly created sub node</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.CreateSubNode.aDesc">
+<short>The description of the sub node</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceTreeNode.CreateResource">
+<short>Creates a new resource</short>
+<descr>
+<p>This method creates a new resource.</p>
+<p>A new resource is created and its type, name and language id are determined from the ancestor nodes in the tree hierarchy.</p>
+<p>Usually <var>CreateResource</var> is called by resource readers that read files in which resources are stored as trees.</p>
+<remark>This method is meaningful only when called on leaf nodes (language id nodes).</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.IsLeaf"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.CreateResource.Result">
+<short>The newly created resource</short>
+</element>
+
+<!-- procedure Visibility: public -->
+<element name="TResourceTreeNode.Clear">
+<short>Destroys all sub nodes</short>
+<descr>
+<p>This method destroys all sub nodes of the node.</p>
+</descr>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceTreeNode.Remove">
+<short>Removes a resource from the tree</short>
+<descr>
+<p>This method searches for the specified resource and removes it from the tree. If a language ID is not provided, the first resource found that matches <var>aType</var> and <var>aName</var> is returned. The removed resource is then returned.</p>
+<p>If no resource is found, <var>nil</var> is returned.</p>
+<remark>This method should only be called on root nodes (instances of <link id="TRootResTreeNode"/>).</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.Add"/>
+</seealso>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.Remove.Result">
+<short>The removed resource, or <var>nil</var> if not found</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Remove.aType">
+<short>The type of the resource to remove</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Remove.aName">
+<short>The name of the resource to remove</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Remove.aLangID">
+<short>The language ID of the resource to remove</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceTreeNode.Find">
+<short>Searches for a resource</short>
+<descr>
+<p>This method searches for a resource with the given type and name in the tree. If a language ID is not provided, the first resource found that matches <var>aType</var> and <var>aName</var> is returned.</p>
+<p>If no resource is found, <var>nil</var> is returned.</p>
+<remark>This method should only be called on root nodes (instances of <link id="TRootResTreeNode"/>).</remark>
+</descr>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.Find.Result">
+<short>The resource that matches the search criteria</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.aType">
+<short>The type of the resource to search for</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.aName">
+<short>The name of the resource to search for</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.Find.aLangID">
+<short>The language ID of the resource to search for</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceTreeNode.FindFreeID">
+<short>Find a free ID to be used as a resource name</short>
+<descr>
+<p>This method is used to find an available ID to be used as a name for a resource, given a resource type. It is used internally by <link id="resource.TResources.AddAutoID">AddAutoID</link> method of <link id="resource.TResources">TResources</link>.</p>
+<remark>This method should only be called on root nodes (instances of <link id="TRootResTreeNode"/>).</remark>
+</descr>
+<errors>
+<p>If there are no free ids left for the given resource type, an <link id="resource.ENoMoreFreeIDsException">ENoMoreFreeIDsException</link> is raised.</p>
+</errors>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.FindFreeID.Result">
+<short>A new resource ID</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.FindFreeID.aType">
+<short>The type of the resource</short>
+</element>
+
+<!-- function Visibility: public -->
+<element name="TResourceTreeNode.IsLeaf">
+<short>Reports whether the node is a leaf node.</short>
+<descr>
+<p>Returns <var>true</var> if the node is a leaf node. A leaf node is a language ID node.</p>
+</descr>
+</element>
+
+<!-- function result Visibility: default -->
+<element name="TResourceTreeNode.IsLeaf.Result">
+<short><var>True</var> if the node is a leaf node</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.Desc">
+<short>The description of the node</short>
+<descr>
+<p>The description of a node identifies that node. According to the type of the node, it can be a resource type, name or language id.</p>
+</descr>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.NamedCount">
+<short>The number of named sub nodes of the node</short>
+<seealso>
+<link id="TResourceTreeNode.NamedEntries"/>
+<link id="TResourceTreeNode.IDCount"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.NamedEntries">
+<short>Indexed array of named sub nodes of the node</short>
+<descr>
+<p>This property can be used to access all named sub nodes in the node.</p>
+<remark>This array is 0-based: valid elements range from 0 to <link id="TResourceTreeNode.NamedCount">NamedCount</link>-1.</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.NamedCount"/>
+<link id="TResourceTreeNode.IDEntries"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.NamedEntries.index">
+<short></short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.IDCount">
+<short>The number of ID sub nodes of the node</short>
+<seealso>
+<link id="TResourceTreeNode.IDEntries"/>
+<link id="TResourceTreeNode.NamedCount"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.IDEntries">
+<short>Indexed array of ID sub nodes of the node</short>
+<descr>
+<p>This property can be used to access all ID sub nodes in the node.</p>
+<remark>This array is 0-based: valid elements range from 0 to <link id="TResourceTreeNode.IDCount">IDCount</link>-1.</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.IDCount"/>
+<link id="TResourceTreeNode.NamedEntries"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TResourceTreeNode.IDEntries.index">
+<short></short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.NameRVA">
+<short>To be used by readers and writers</short>
+<descr>
+<p>This property can be freely used by resource readers and writers to store a file offset or address needed to load or write other data, since it isn't used by <link id="TResourceTreeNode"/> or <link id="resource.TResources">TResources</link>.</p>
+<remark>Do not rely on the value of this property when accessing a new tree: other readers or writers could have changed it for their internal operations.</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.SubDirRVA"/>
+<link id="TResourceTreeNode.DataRVA"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.SubDirRVA">
+<short>To be used by readers and writers</short>
+<descr>
+<p>This property can be freely used by resource readers and writers to store a file offset or address needed to load or write other data, since it isn't used by <link id="TResourceTreeNode"/> or <link id="resource.TResources">TResources</link>.</p>
+<remark>Do not rely on the value of this property when accessing a new tree: other readers or writers could have changed it for their internal operations.</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.NameRVA"/>
+<link id="TResourceTreeNode.DataRVA"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.DataRVA">
+<short>To be used by readers and writers</short>
+<descr>
+<p>This property can be freely used by resource readers and writers to store a file offset or address needed to load or write other data, since it isn't used by <link id="TResourceTreeNode"/> or <link id="resource.TResources">TResources</link>.</p>
+<remark>Do not rely on the value of this property when accessing a new tree: other readers or writers could have changed it for their internal operations.</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.NameRVA"/>
+<link id="TResourceTreeNode.SubDirRVA"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TResourceTreeNode.Data">
+<short>The resource contained in this node</short>
+<descr>
+<p>This property references the resource contained in this node.</p>
+<remark>This property is meaningful only on leaf nodes (language id nodes).</remark>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.IsLeaf"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="TRootResTreeNode">
+<short>The root node in a resource tree</short>
+<descr>
+<p>This node represents the root node of a resource tree.</p>
+<p>It is the only node which must be created with its constructor: other nodes in the tree are automatically created when adding a resource, or calling <link id="TResourceTreeNode.CreateSubNode">CreateSubNode</link> method of their parent.</p>
+<p>Normally all search, add and delete operations on the tree are performed by calling methods of this node.</p>
+</descr>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TRootResTreeNode.Create">
+<short>Creates a new root node</short>
+<descr>
+<p>This method creates a new tree, represented by a root node without children.</p>
+<p>Other nodes in the tree are automatically created when adding a resource, or calling <link id="TResourceTreeNode.CreateSubNode">CreateSubNode</link> method of their parent.</p>
+</descr>
+<seealso>
+<link id="TResourceTreeNode.CreateSubNode"/>
+<link id="TResourceTreeNode.Add"/>
+</seealso>
+</element>
+
+</module> <!-- resourcetree -->
+
+</package>
+</fpdoc-descriptions>

+ 46 - 0
packages/fcl-res/xml/resreader.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    resreader
+  ====================================================================
+-->
+
+<module name="resreader">
+<short>Contains a resource reader for .res files</short>
+<descr>
+<p>This unit contains <link id="TResResourceReader"/>, a <link id="resource.TAbstractResourceReader">TAbstractResourceReader</link> descendant that is able to read .res resource files.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TResResourceReader"/> with <link id="resource.TResources">TResources</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TResResourceReader">
+<short>.res resource reader</short>
+<descr>
+<p>This class provides a reader for .res resource files.</p>
+<p>A .res file is a standard Windows file type that contains resources. This is not an object file format, so it's not suitable for being linked with other object files. For this reason, it is a good choice for a platform-independent format to store resources.</p>
+</descr>
+<seealso>
+<link id="resource.TAbstractResourceReader">TAbstractResourceReader</link>
+<link id="reswriter.TResResourceWriter">TResResourceWriter</link>
+</seealso>
+</element>
+
+</module> <!-- resreader -->
+
+</package>
+</fpdoc-descriptions>

+ 46 - 0
packages/fcl-res/xml/reswriter.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    reswriter
+  ====================================================================
+-->
+
+<module name="reswriter">
+<short>Contains a resource writer for .res files</short>
+<descr>
+<p>This unit contains <link id="TResResourceWriter"/>, a <link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link> descendant that is able to write .res resource files.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TResResourceWriter"/> with <link id="resource.TResources">TResources</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="TResResourceWriter">
+<short>.res resource writer</short>
+<descr>
+<p>This class provides a writer for .res resource files.</p>
+<p>A .res file is a standard Windows file type that contains resources. This is not an object file format, so it's not suitable for being linked with other object files. For this reason, it is a good choice for a platform-independent format to store resources.</p>
+</descr>
+<seealso>
+<link id="resource.TAbstractResourceWriter">TAbstractResourceWriter</link>
+<link id="resreader.TResResourceReader">TResResourceReader</link>
+</seealso>
+</element>
+
+</module> <!-- reswriter -->
+
+</package>
+</fpdoc-descriptions>

+ 169 - 0
packages/fcl-res/xml/stringtableresource.xml

@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<fpdoc-descriptions>
+<package name="fcl-res">
+
+<!--
+  ====================================================================
+    stringtableresource
+  ====================================================================
+-->
+
+<module name="stringtableresource">
+<short>Contains a string table resource type</short>
+<descr>
+<p>This unit contains <link id="TStringTableResource"/>, a <link id="resource.TAbstractResource">TAbstractResource</link> descendant specialized in handling resource of type <link id="resource.RT_STRING">RT_STRING</link>.</p>
+<p>Adding this unit to a program's <var>uses</var> clause registers class <link id="TStringTableResource"/> for type <link id="resource.RT_STRING">RT_STRING</link> with <link id="resfactory.TResourceFactory">TResourceFactory</link>.</p>
+</descr>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="Classes">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="SysUtils">
+</element>
+
+<!-- unresolved type reference Visibility: default -->
+<element name="resource">
+</element>
+
+<!-- object Visibility: default -->
+<element name="EStringTableResourceException">
+<short>Base class for string table resource-related exceptions</short>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EStringTableNameNotAllowedException">
+<short>The name of the resource isn't allowed</short>
+<descr>
+<p>This exception is raised by constructor <link id="TStringTableResource.Create"/> if the name of the resource isn't of type <link id="resource.TDescType.dtID">dtID</link> and/or its name is not in the range 1-4096.</p>
+</descr>
+<seealso>
+<link id="TStringTableResource.Create"/>
+</seealso>
+</element>
+
+<!-- object Visibility: default -->
+<element name="EStringTableIndexOutOfBoundsException">
+<short>The ID of the string is out of range</short>
+<descr>
+<p>This exception is raised when the id specified to access a string of <link id="TStringTableResource.Strings"/> property is not in the range <link id="TStringTableResource.FirstID"/> - <link id="TStringTableResource.LastID"/>.</p>
+</descr>
+<seealso>
+<link id="TStringTableResource"/>
+<link id="TStringTableResource.Strings"/>
+<link id="TStringTableResource.FirstID"/>
+<link id="TStringTableResource.LastID"/>
+</seealso>
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SNameNotAllowed">
+</element>
+
+<!-- resource string Visibility: default -->
+<element name="SIndexOutOfBounds">
+</element>
+
+
+<!-- object Visibility: default -->
+<element name="TStringTableResource">
+<short>String table resource type</short>
+<descr>
+<p>This class represents a resource of type <link id="resource.RT_STRING">RT_STRING</link>.</p>
+<p>A string table is a resource containing strings, identified by an integer id in the range 0-65535. A string table contains exactly 16 strings, and its name is an ID in the range 1-4096, determined by the highest 12 bits of the strings ID it contains, plus one. That is, a string table with 1 as name holds strings with IDs from 0 to 15, string table 2 contains strings with IDs from 16 to 31 and so on. There is no difference between an empty string and a non-existant string.</p>
+<p>For these reasons, it is not possible to set the name of a string table: it is autogenerated from the value of <link id="TStringTableResource.FirstID">FirstID</link> property. Moreover, <link id="TStringTableResource.Count">Count</link> property is always 16.</p>
+<p><link id="TStringTableResource.Strings">Strings</link> property is provided to access and modify individual strings.</p>
+<remark>This class doesn't allow its type to be changed to anything else than <link id="resource.RT_BITMAP">RT_BITMAP</link>. Its name can't be changed too. Attempts to do so result in a <link id="resource.EResourceDescChangeNotAllowedException">EResourceDescChangeNotAllowedException</link>.</remark>
+</descr>
+</element>
+
+<!-- constructor Visibility: public -->
+<element name="TStringTableResource.Create">
+<short>Creates a new string table resource</short>
+<descr>
+<p>Please note that <var>aType</var> parameter is not used, since this class always uses <link id="resource.RT_STRING">RT_STRING</link> as type.</p>
+<remark><var>aName</var> must be a <link id="resource.TResourceDesc">TResourceDesc</link> of type <link id="resource.TDescType.dtID">dtID</link> and its value must be in the range 1-4096, otherwise an <link id="EStringTableNameNotAllowedException"/> exception is raised.</remark>
+</descr>
+<errors>
+<p>If <var>aName</var> is not of type <link id="resource.TDescType.dtID">dtID</link> and/or its value isn't in the range 1-4096, an <link id="EStringTableNameNotAllowedException"/> exception is raised.</p>
+</errors>
+<seealso>
+<link id="TStringTableResource.FirstID"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TStringTableResource.Create.aType">
+<short>Ignored. Can be <var>nil</var>.</short>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TStringTableResource.Create.aName">
+<short>The name of the resource. Must be of type dtID and in the range 1-4096</short>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TStringTableResource.FirstID">
+<short>The ID of first the string contained in the string table</short>
+<descr>
+<p>This property holds the value of the ID of the first string of the table. It is a multiple of 16.</p>
+<p>The name of the resource is determined by this property, so changing FirstID also changes the resource name.</p>
+<remark>If an attempt of setting this property to an integer that isn't a multiple of 16 is made, the value is automatically corrected to the closest multiple of 16 less than the value specified (e.g. setting it to 36 sets it to 32).</remark>
+</descr>
+<seealso>
+<link id="TStringTableResource"/>
+<link id="TStringTableResource.LastID"/>
+<link id="TStringTableResource.Strings"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TStringTableResource.LastID">
+<short>The ID of the last string contained in the string table</short>
+<descr>
+<p>The value of this property is always <link id="TStringTableResource.FirstID">FirstID</link>+15.</p>
+</descr>
+<seealso>
+<link id="TStringTableResource"/>
+<link id="TStringTableResource.FirstID"/>
+<link id="TStringTableResource.Strings"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TStringTableResource.Count">
+<short>The number of strings contained in the string table</short>
+<descr>
+<p>Since a string table resource always contains exactly 16 strings, this property is always 16</p>
+</descr>
+<seealso>
+<link id="TStringTableResource"/>
+<link id="TStringTableResource.FirstID"/>
+</seealso>
+</element>
+
+<!-- property Visibility: public -->
+<element name="TStringTableResource.Strings">
+<short>Indexed array of strings in the string table</short>
+<descr>
+<p>This property can be used to access all strings in the object.</p>
+<remark>Strings are accessed by their ID: valid elements range from <link id="TStringTableResource.FirstID">FirstID</link> to <link id="TStringTableResource.LastID">LastID</link>. If the index specified isn't in this range, an <link id="EStringTableIndexOutOfBoundsException"/> exception is raised.</remark>
+<remark>If you need to access <link id="resource.TAbstractResource.RawData">RawData</link> after you modified strings, be sure to call <link id="resource.TAbstractResource.UpdateRawData">UpdateRawData</link> first. This isn't needed however when resource is written to a stream, since <link id="resource.TResources">TResources</link> takes care of it.</remark>
+</descr>
+<seealso>
+<link id="TStringTableResource"/>
+<link id="TStringTableResource.FirstID"/>
+<link id="TStringTableResource.LastID"/>
+</seealso>
+</element>
+
+<!-- argument Visibility: default -->
+<element name="TStringTableResource.Strings.id">
+<short>The ID of the string to be accessed</short>
+</element>
+
+</module> <!-- stringtableresource -->
+
+</package>
+</fpdoc-descriptions>

部分文件因文件數量過多而無法顯示