Browse Source

Added IFF/ILBM loading. Resolves #11.

Brucey 3 years ago
parent
commit
9af2331ba5
100 changed files with 14749 additions and 0 deletions
  1. 41 0
      ilbm.mod/common.bmx
  2. BIN
      ilbm.mod/examples/Kickstart11.iff
  3. BIN
      ilbm.mod/examples/PLANE02.RGB
  4. 53 0
      ilbm.mod/examples/example_01.bmx
  5. 61 0
      ilbm.mod/glue.c
  6. 127 0
      ilbm.mod/ilbm.bmx
  7. 1 0
      ilbm.mod/libamivideo/AUTHORS
  8. 18 0
      ilbm.mod/libamivideo/COPYING
  9. 0 0
      ilbm.mod/libamivideo/ChangeLog
  10. 365 0
      ilbm.mod/libamivideo/INSTALL
  11. 1 0
      ilbm.mod/libamivideo/Makefile.am
  12. 0 0
      ilbm.mod/libamivideo/NEWS
  13. 607 0
      ilbm.mod/libamivideo/README.md
  14. 7 0
      ilbm.mod/libamivideo/bootstrap
  15. 20 0
      ilbm.mod/libamivideo/configure.ac
  16. 78 0
      ilbm.mod/libamivideo/release.nix
  17. 1679 0
      ilbm.mod/libamivideo/src/Doxyfile
  18. 9 0
      ilbm.mod/libamivideo/src/Makefile.am
  19. 11 0
      ilbm.mod/libamivideo/src/libamivideo.pc.in
  20. 22 0
      ilbm.mod/libamivideo/src/libamivideo.sln
  21. 4 0
      ilbm.mod/libamivideo/src/libamivideo/Makefile.am
  22. 40 0
      ilbm.mod/libamivideo/src/libamivideo/amivideotypes.h
  23. 40 0
      ilbm.mod/libamivideo/src/libamivideo/libamivideo.def
  24. 92 0
      ilbm.mod/libamivideo/src/libamivideo/libamivideo.vcxproj
  25. 47 0
      ilbm.mod/libamivideo/src/libamivideo/libamivideo.vcxproj.filters
  26. 197 0
      ilbm.mod/libamivideo/src/libamivideo/palette.c
  27. 178 0
      ilbm.mod/libamivideo/src/libamivideo/palette.h
  28. 457 0
      ilbm.mod/libamivideo/src/libamivideo/screen.c
  29. 365 0
      ilbm.mod/libamivideo/src/libamivideo/screen.h
  30. 82 0
      ilbm.mod/libamivideo/src/libamivideo/viewportmode.c
  31. 101 0
      ilbm.mod/libamivideo/src/libamivideo/viewportmode.h
  32. 7 0
      ilbm.mod/libamivideo/tests/Makefile.am
  33. 61 0
      ilbm.mod/libamivideo/tests/chunky.c
  34. 1 0
      ilbm.mod/libamivideo/version
  35. 1 0
      ilbm.mod/libiff/AUTHORS
  36. 18 0
      ilbm.mod/libiff/COPYING
  37. 0 0
      ilbm.mod/libiff/ChangeLog
  38. 365 0
      ilbm.mod/libiff/INSTALL
  39. 1 0
      ilbm.mod/libiff/Makefile.am
  40. 0 0
      ilbm.mod/libiff/NEWS
  41. 1 0
      ilbm.mod/libiff/README
  42. 606 0
      ilbm.mod/libiff/README.md
  43. 7 0
      ilbm.mod/libiff/bootstrap
  44. 34 0
      ilbm.mod/libiff/configure.ac
  45. 1424 0
      ilbm.mod/libiff/doc/IFF.asc
  46. 3 0
      ilbm.mod/libiff/doc/Makefile.am
  47. 100 0
      ilbm.mod/libiff/release.nix
  48. 1679 0
      ilbm.mod/libiff/src/Doxyfile
  49. 9 0
      ilbm.mod/libiff/src/Makefile.am
  50. 14 0
      ilbm.mod/libiff/src/iffjoin/Makefile.am
  51. 87 0
      ilbm.mod/libiff/src/iffjoin/iffjoin.vcxproj
  52. 30 0
      ilbm.mod/libiff/src/iffjoin/iffjoin.vcxproj.filters
  53. 114 0
      ilbm.mod/libiff/src/iffjoin/join.c
  54. 35 0
      ilbm.mod/libiff/src/iffjoin/join.h
  55. 154 0
      ilbm.mod/libiff/src/iffjoin/main.c
  56. 14 0
      ilbm.mod/libiff/src/iffpp/Makefile.am
  57. 86 0
      ilbm.mod/libiff/src/iffpp/iffpp.vcxproj
  58. 30 0
      ilbm.mod/libiff/src/iffpp/iffpp.vcxproj.filters
  59. 138 0
      ilbm.mod/libiff/src/iffpp/main.c
  60. 60 0
      ilbm.mod/libiff/src/iffpp/pp.c
  61. 36 0
      ilbm.mod/libiff/src/iffpp/pp.h
  62. 11 0
      ilbm.mod/libiff/src/libiff.pc.in
  63. 40 0
      ilbm.mod/libiff/src/libiff.sln
  64. 3 0
      ilbm.mod/libiff/src/libiff/Makefile.am
  65. 134 0
      ilbm.mod/libiff/src/libiff/cat.c
  66. 176 0
      ilbm.mod/libiff/src/libiff/cat.h
  67. 282 0
      ilbm.mod/libiff/src/libiff/chunk.c
  68. 172 0
      ilbm.mod/libiff/src/libiff/chunk.h
  69. 61 0
      ilbm.mod/libiff/src/libiff/error.c
  70. 79 0
      ilbm.mod/libiff/src/libiff/error.h
  71. 88 0
      ilbm.mod/libiff/src/libiff/extension.c
  72. 93 0
      ilbm.mod/libiff/src/libiff/extension.h
  73. 291 0
      ilbm.mod/libiff/src/libiff/form.c
  74. 215 0
      ilbm.mod/libiff/src/libiff/form.h
  75. 263 0
      ilbm.mod/libiff/src/libiff/group.c
  76. 237 0
      ilbm.mod/libiff/src/libiff/group.h
  77. 90 0
      ilbm.mod/libiff/src/libiff/id.c
  78. 90 0
      ilbm.mod/libiff/src/libiff/id.h
  79. 154 0
      ilbm.mod/libiff/src/libiff/iff.c
  80. 128 0
      ilbm.mod/libiff/src/libiff/iff.h
  81. 66 0
      ilbm.mod/libiff/src/libiff/ifftypes.h
  82. 53 0
      ilbm.mod/libiff/src/libiff/ifftypes.h.in
  83. 255 0
      ilbm.mod/libiff/src/libiff/io.c
  84. 166 0
      ilbm.mod/libiff/src/libiff/io.h
  85. 120 0
      ilbm.mod/libiff/src/libiff/libiff.def
  86. 112 0
      ilbm.mod/libiff/src/libiff/libiff.vcxproj
  87. 107 0
      ilbm.mod/libiff/src/libiff/libiff.vcxproj.filters
  88. 234 0
      ilbm.mod/libiff/src/libiff/list.c
  89. 192 0
      ilbm.mod/libiff/src/libiff/list.h
  90. 98 0
      ilbm.mod/libiff/src/libiff/prop.c
  91. 137 0
      ilbm.mod/libiff/src/libiff/prop.h
  92. 165 0
      ilbm.mod/libiff/src/libiff/rawchunk.c
  93. 142 0
      ilbm.mod/libiff/src/libiff/rawchunk.h
  94. 37 0
      ilbm.mod/libiff/src/libiff/util.c
  95. 46 0
      ilbm.mod/libiff/src/libiff/util.h
  96. 123 0
      ilbm.mod/libiff/tests/Makefile.am
  97. 105 0
      ilbm.mod/libiff/tests/bye.c
  98. 55 0
      ilbm.mod/libiff/tests/bye.h
  99. 82 0
      ilbm.mod/libiff/tests/catdata.c
  100. 29 0
      ilbm.mod/libiff/tests/catdata.h

+ 41 - 0
ilbm.mod/common.bmx

@@ -0,0 +1,41 @@
+' Copyright (c) 2022 Bruce A Henderson
+' 
+' Permission is hereby granted, free of charge, to any person obtaining a copy
+' of this software and associated documentation files (the "Software"), to deal
+' in the Software without restriction, including without limitation the rights
+' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+' copies of the Software, and to permit persons to whom the Software is
+' furnished to do so, subject to the following conditions:
+' 
+' The above copyright notice and this permission notice shall be included in
+' all copies or substantial portions of the Software.
+' 
+' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+' THE SOFTWARE.
+' 
+SuperStrict
+
+Import "source.bmx"
+
+Extern
+	Function bmx_ilbm_load_iff:Byte Ptr(callbacks:Object)
+	Function bmx_ilbm_get_image:SIlbmImageOut Ptr(ilbmImage:Byte Ptr, pixelScaleFactor:UInt)
+	Function ILBM_extractImages:Byte Ptr Ptr(handle:Byte Ptr, imagesLength:UInt Var)
+	Function ILBM_checkImages:Int(handle:Byte Ptr, images:Byte Ptr Ptr, imagesLength:UInt)
+	Function ILBM_freeImages(images:Byte Ptr Ptr, imagesLength:UInt)
+	Function ILBM_free(handle:Byte Ptr)
+End Extern
+
+Struct SIlbmImageOut
+	Field width:UInt
+	Field height:UInt
+	Field depth:UInt
+	Field colorsCount:UInt
+	Field palette:Byte Ptr
+	Field pixels:Byte Ptr
+End Struct

BIN
ilbm.mod/examples/Kickstart11.iff


BIN
ilbm.mod/examples/PLANE02.RGB


+ 53 - 0
ilbm.mod/examples/example_01.bmx

@@ -0,0 +1,53 @@
+SuperStrict
+
+Framework SDL.SDLRenderMax2D
+Import Image.ILBM
+
+Local w:Int = DesktopWidth() * .75
+Local h:Int = DeskTopHeight() * .75
+
+Graphics w, h, 0
+
+AutoMidHandle(True)
+
+Local img1:TImage = Loader("Kickstart11.iff", w, h)
+Local img2:TImage = Loader("PLANE02.RGB", w, h)
+
+If Not img1 Or Not img2 Then
+	Print "Failed to load image"
+	End
+End If
+
+Local image:Int
+Local img:TImage = img1
+
+While Not KeyDown(Key_ESCAPE)
+
+	Cls
+
+	If KeyHit(KEY_SPACE) Then
+		image = Not image
+		If image Then
+			img = img2
+		Else
+			img = img1
+		End If
+	End If
+
+	DrawImage img, w / 2, h / 2
+
+	Flip
+
+Wend
+
+Function Loader:TImage(path:String, maxWidth:Int, maxHeight:Int)
+	Local pix:TPixmap = LoadPixmap( path )
+	If pix Then
+		If pix.width > maxWidth Or pix.height > maxHeight Then
+			Local ratio:Float = Min(maxWidth / Float(pix.width), maxHeight / Float(pix.height))
+			pix = ResizePixmap(pix, Int(pix.width * ratio), Int(pix.height * ratio))
+		End If
+		Return LoadImage(pix)
+	End If
+End Function
+

+ 61 - 0
ilbm.mod/glue.c

@@ -0,0 +1,61 @@
+/*
+  Copyright (c) 2022 Bruce A Henderson
+ 
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+  
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+  
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+  THE SOFTWARE.
+*/ 
+#include "libilbm/ilbm.h"
+#include "libilbm/ilbmimage.h"
+#include "libamivideo/screen.h"
+#include "image.h"
+
+#include "brl.mod/blitz.mod/blitz.h"
+
+extern int image_ilbm_TIlbmIoCallbacks__Read(BBObject * cb, char * data,int size);
+extern int image_ilbm_TIlbmIoCallbacks__Write(BBObject * cb, char * data,int size);
+extern int image_ilbm_TIlbmIoCallbacks__Eof(BBObject * cb);
+
+IFF_Chunk * bmx_ilbm_load_iff(BBObject * cb) {
+
+	io_callbacks callbacks;
+	callbacks.read = image_ilbm_TIlbmIoCallbacks__Read;
+	callbacks.write = image_ilbm_TIlbmIoCallbacks__Write;
+	callbacks.eof = image_ilbm_TIlbmIoCallbacks__Eof;
+
+    io_context context;
+    context.userData = cb;
+    context.io = callbacks;
+
+	return ILBM_readIo(&context);
+}
+
+ilbm_image_out * bmx_ilbm_get_image(ILBM_Image * ilbmImage, unsigned int pixelScaleFactor) {
+    amiVideo_Screen screen;
+
+    SDL_ILBM_initScreenFromImage(ilbmImage, &screen);
+
+    if (pixelScaleFactor == 0) {
+        pixelScaleFactor = amiVideo_autoSelectLowresPixelScaleFactor(screen.viewportMode);
+    }
+
+    ilbm_image_out * image = SDL_ILBM_generateSurfaceFromScreen(ilbmImage, &screen, SDL_ILBM_FORMAT_RGB, pixelScaleFactor);
+
+    amiVideo_cleanupScreen(&screen);
+ 
+    return image;
+}

+ 127 - 0
ilbm.mod/ilbm.bmx

@@ -0,0 +1,127 @@
+' Copyright (c) 2022 Bruce A Henderson
+' 
+' Permission is hereby granted, free of charge, to any person obtaining a copy
+' of this software and associated documentation files (the "Software"), to deal
+' in the Software without restriction, including without limitation the rights
+' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+' copies of the Software, and to permit persons to whom the Software is
+' furnished to do so, subject to the following conditions:
+' 
+' The above copyright notice and this permission notice shall be included in
+' all copies or substantial portions of the Software.
+' 
+' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+' THE SOFTWARE.
+' 
+SuperStrict
+
+Rem
+bbdoc: Image/ILBM loader
+about:
+The ILBM loader module provides the ability to load ILBM format #pixmaps.
+End Rem
+Module Image.ILBM
+
+ModuleInfo "Version: 1.00"
+ModuleInfo "License: MIT"
+ModuleInfo "Copyright: libiff/libilbm/libamivideo - 2012 Sander van der Burg"
+ModuleInfo "Copyright: sdl ilbm image - 2012 Sander van der Burg & 2014 Roman Hiestand"
+ModuleInfo "Copyright: Wrapper - 2022 Bruce A Henderson"
+
+ModuleInfo "History: 1.00 Initial Release"
+
+Import BRL.Pixmap
+
+Import "common.bmx"
+
+Private
+
+Type TPixmapLoaderILBM Extends TPixmapLoader
+
+	Method LoadPixmap:TPixmap( stream:TStream ) Override
+	
+		Local pixmap:TPixmap
+	
+		Local cb:TIlbmIoCallbacks = New TIlbmIoCallbacks
+		cb.stream = stream
+		
+		
+		Local chunkPtr:Byte Ptr = bmx_ilbm_load_iff(cb)
+
+		If Not chunkPtr Then
+			Return Null
+		End If
+
+		Local imagesLength:UInt
+		Local imagesPtr:Byte Ptr Ptr = ILBM_extractImages(chunkPtr, imagesLength)
+
+		If Not ILBM_checkImages(chunkPtr, imagesPtr, imagesLength) Or imagesLength = 0 Then
+			ILBM_freeImages(imagesPtr, imagesLength)
+			ILBM_free(chunkPtr)
+			Return Null
+		End If
+
+		Local image:Byte Ptr = imagesPtr[0]
+		Local rgbImage:SIlbmImageOut Ptr = bmx_ilbm_get_image(image, 0)
+
+		If Not rgbImage Then
+			ILBM_freeImages(imagesPtr, imagesLength)
+			ILBM_free(chunkPtr)
+			Return Null
+		End If
+
+		Local pix:TPixmap = CreatePixmap( rgbImage.width, rgbImage.height, PF_RGBA8888, 4 )
+		MemCopy(pix.pixels, rgbImage.pixels, size_T(pix.width * pix.height * 4))
+
+		free_(rgbImage)
+		ILBM_freeImages(imagesPtr, imagesLength)
+		ILBM_free(chunkPtr)
+
+		' set alpha channel
+		Local pixel:Byte Ptr = pix.pixels
+		For Local i:Int = 0 until pix.width * pix.height
+			pixel[3] = 255
+			pixel :+ 4
+		Next
+
+		Return pix
+	End Method
+
+End Type
+
+Type TIlbmIoCallbacks
+
+	Field stream:TStream
+	
+	Method Read:Int(buffer:Byte Ptr, size:Int)
+		Return stream.Read(buffer, size)
+	End Method
+	
+	Method Write:Int(buffer:Byte Ptr, size:Int)
+		Return stream.Write(buffer, size)
+	End Method
+	
+	Method Eof:Int()
+		Return stream.Eof()
+	End Method
+
+	Function _Read:Int(cb:TIlbmIoCallbacks, buffer:Byte Ptr, size:Int) { nomangle }
+		Return cb.Read(buffer, size)
+	End Function
+
+	Function _Write:Int(cb:TIlbmIoCallbacks, buffer:Byte Ptr, size:Int) { nomangle }
+		Return cb.Write(buffer, size)
+	End Function
+
+	Function _Eof:Int(cb:TIlbmIoCallbacks) { nomangle }
+		Return cb.Eof()
+	End Function
+	
+End Type
+
+New TPixmapLoaderILBM

+ 1 - 0
ilbm.mod/libamivideo/AUTHORS

@@ -0,0 +1 @@
+Sander van der Burg <[email protected]>

+ 18 - 0
ilbm.mod/libamivideo/COPYING

@@ -0,0 +1,18 @@
+Copyright (c) 2012 Sander van der Burg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 0 - 0
ilbm.mod/libamivideo/ChangeLog


+ 365 - 0
ilbm.mod/libamivideo/INSTALL

@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+

+ 1 - 0
ilbm.mod/libamivideo/Makefile.am

@@ -0,0 +1 @@
+SUBDIRS = src tests

+ 0 - 0
ilbm.mod/libamivideo/NEWS


+ 607 - 0
ilbm.mod/libamivideo/README.md

@@ -0,0 +1,607 @@
+libamivideo
+===========
+Commodore Amiga hardware uses a different means of storing and displaying
+graphics compared to "modern hardware", such as PCs.
+
+Pixels
+------
+Historically, the most widely used display mode for games and many multimedia
+applications on PCs is a 320x200 resolution screen with a 256 color palette. In
+this display mode, pixels are encoded as bytes in which each byte value refers
+to an index of the palette.
+
+These days, PCs have much more system resources and can directly use any possible
+color value for a pixel. The most common way to support this by encoding a pixel
+as 4 bytes in which three byte refers to the red, blue and green intensity
+values. One byte is used for padding.
+
+Amiga hardware uses a completely different approach -- pixels are encoded as
+bitplanes rather than bytes.
+
+When using bitplane encoding, an image is stored multiple times in memory. In
+every image occurence a bit represents a pixel. In the first occurence, a bit is
+the least significant bit of an index a value. In the last occurence a bit is the
+most significant bit of an index value. By adding all the bits together we can
+determine the index value of the palette to determine a pixel's color value.
+
+Palette
+-------
+Color values on PCs are stored in 4-byte color registers, in which one byte
+is used for the red color intensity, one for green color intensity and one
+for blue color intensity. One byte is used for padding.
+
+The Amiga display have a palette with predefined color values that are stored in
+either 32 color registers (`OCS` and `ECS` chipset) containing 12-bit color
+values or 256 color registers (`AGA` chipset) storing 32-bit color values.
+
+Furthermore, the Amiga video chips have special screen modes to squeeze more
+colors out of the amount of color registers available. The Extra Half Brite (EHB)
+screen mode is capable of displaying 64 colors out of a predefined 32, in which
+the last 32 colors values have half of the intensity of the first 32 colors.
+
+The Hold-and-Modify (HAM) screen mode is used to modify a color component of the
+previous adjacent pixel or to provide a new color from the given palette. This
+screen mode makes it possible to display all possible color values with some
+loss of quality.
+
+Resolutions
+-----------
+In addition to colors, resolutions are also different on the Amiga compared to
+modern platforms.
+
+On PCs, resolutions refer to the amount of pixels per scanline and the amount
+of scanlines per screen.
+
+On the Amiga, resolutions only refer to the amount of pixels per scanline and
+only a few fixed resolutions can be used.
+
+For example, a high resolution screen has twice the amount of pixels per scanline
+compared to a low resolution screen. A super hires screen has double the amount
+of pixels per scanline compared to a high resolution screen. Moreover, a low
+resolution pixel is twice a wide as a high resolution pixel and so on.
+
+Vertically, there are only two options. In principle, there are a fixed amount of
+scanlines on a display. The amount of scanlines can be doubled, using a so-called
+_interlace_ screen mode. However, interlace screen modes have a big drawback --
+they draw the odd scanlines in one frame and the even ones in another. On
+displays with a short after glow, flickering may be observed.
+
+If we would convert an Amiga image directly to a PC display, we may observe odd
+results in some cases. For example, a non-interlaced high resolution image looks
+twice as wide on a PC display than on an Amiga display. To give it the same look,
+we must correct its aspect ratio by doubling the amount of scanlines on the PC
+display.
+
+Features
+========
+The purpose of this library is to cope with the differences of PCs and Amiga
+displays in an easy way -- it acts as a conversion library for the Amiga video
+chips to modern hardware and vice versa. More specifically, this library offers
+the following features:
+
+* Converting a 12/24-bit color palette to a 32-bit true color palette and vice versa
+* Emulation of the Extra Half-brite (EHB) and Hold-and-Modify (HAM) screen modes
+* Converting bitplanes to chunky pixels and vice versa
+* Converting bitplanes to true color pixels
+* Correcting the aspect ratio of Amiga images
+
+In principle, this library does not do any allocation of source or destination
+surfaces that contain graphics data, but acts as an _adapter_ that is placed in
+the middle of these two instances that are already created by other means.
+
+The source and destination services can be nearly anything, such as something
+generated by a library or a real Amiga viewport. The only requirement is that
+they must store pixel data in their "raw" format that the functions of this
+library can access.
+
+Converting planar graphics to chunky/RGB graphics
+=================================================
+This section convers a simple example in which we convert an Amiga viewport
+surface to something that can be displayed on a PC.
+
+Acquiring a planar graphics source
+----------------------------------
+We use the following imaginary struct as example representing an Amiga viewport:
+
+```C
+typedef struct Color
+{
+    UBYTE r, g, b;
+}
+Color;
+
+struct
+{
+    ULONG width;
+    ULONG height;
+    UWORD bitplaneDepth;
+    ULONG viewportMode;
+    
+    Color color[32];
+    UBYTE *bitplanes[6];
+}
+viewport;
+```
+
+The above struct represents an Amiga viewport having a specific width
+(in pixels), height (in scanlines), a bitplane depth (corresponding to the amount
+of colors used), a viewport mode value that contains Amiga specific display
+mode bits, such as extra half-brite mode, and a palette consisting of 32 colors.
+
+The last member of the struct is an array containing bitplane encoded pixels.
+
+Creating a conversion struct instance
+-------------------------------------
+To be able to convert the data in the viewport, we must create an instance of the
+`amiVideo_Screen` struct that acts as an adapter for the conversion processes.
+
+In the following code fragment, we configure a screen instance adopting the
+dimensions, display settings, and palette of the example viewport struct shown
+earlier:
+
+```C
+#include <libamivideo/screen.h>
+
+/* Initialise screen with screen settings */
+amiVideo_Screen screen;
+
+/*
+ * Create a screen conversion struct instance with the viewport's width,
+ * height, bitplane depth and viewport mode. We use 4-bits per color
+ * component to simulate OCS/ECS display modes.
+ */
+amiVideo_initScreen(&screen, viewport->width, viewport->height, viewport->bitplaneDepth, 4, viewport->viewportMode);
+
+/* Set the bitplane palette to the viewport's palette */
+amiVideo_setBitplanePaletteColors(&screen.palette, color, 32);
+
+/* Set the bitplane pointers to the pointers in the viewport */
+amiVideo_setScreenBitplanePointers(&screen, viewport->bitplanes);
+```
+
+As a sidenote: In the above code fragment we use
+`amiVideo_setScreenBitplanePointers()` to link the adapter to a pointer
+interface. If a contiguous block of planar data is used then
+`amiVideo_setScreenBitplanes()` is typically more useful, which automatically
+sets the pointers to the right locations in the given memory block.
+
+After configuring the screen adapter, we can use it to convert the viewport
+to something that can be displayed on modern hardware, with or without correcting
+its aspect ratio. In the next sections, we explain how this can be done.
+
+Allocating a target surface and performing the conversion
+---------------------------------------------------------
+In the examples used in the following sub sections, we use the [SDL](http://www.libsdl.org)
+library to allocate a target pixel surface storing pixels in the converted
+format.
+
+There are various output formats supported. Some of them are more memory
+efficient and have certain restrictions, others give a better equivalent pixel
+experience on modern platforms. Moreover, we show how the actual conversion
+process can be executed.
+
+Converting to uncorrected chunky pixels format
+----------------------------------------------
+The simplest output format is uncorrected chunky pixels in which each output
+pixel is a byte referring to an index of the palette. Moreover, color components
+of the palette are converted from 4 bits to 8 bits:
+
+```C
+#include <SDL.h>
+
+/* Create a SDL surface having 8 bits per pixel in which the output is stored */
+SDL_Surface *surface = SDL_CreateRGBSurface(0, screen.width, screen.height, 8, 0, 0, 0, 0);
+
+/*
+ * Convert the colors of the palette from 4 bits per color component to 8
+ * bits per color component.
+ */
+amiVideo_convertBitplaneColorsToChunkyFormat(&screen.palette);
+
+/* Set the palette of the target SDL surface */
+if(SDL_SetPaletteColors(surface->format->palette, (SDL_Color*)screen.palette.chunkyFormat.color, 0, screen.palette.chunkyFormat.numOfColors) != 0)
+{
+    fprintf(stderr, "Cannot set palette of the surface!\n");
+    return 1;
+}
+
+/* Sets the uncorrected chunky pixels pointer of the conversion struct to that of the SDL pixel surface */
+amiVideo_setScreenUncorrectedChunkyPixelsPointer(&screen, surface->pixels, surface->pitch);
+
+/* Convert the bitplanes to chunky pixels */
+
+if(SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) != 0)
+{
+    fprintf(stderr, "Cannot lock the surface!\n");
+    return 1;
+}
+
+amiVideo_convertScreenBitplanesToChunkyPixels(&screen);
+
+if(SDL_MUSTLOCK(surface))
+    SDL_UnlockSurface(surface);
+```
+
+Converting to uncorrected RGB pixels format
+-------------------------------------------
+Chunky graphics output format is memory efficient and suffices for nearly all
+Amiga screen modes, except for the HAM screenmodes which support more than 256
+colors due to a compression technique and 24 and 32 bitplanes modes which are
+used by so-called deep ILBM images.
+
+To convert to RGB in which every 4 bytes refer to a pixel's color value, we can
+do the following:
+
+```C
+#include <SDL.h>
+
+/* Create a SDL surface having 24 bits per pixel in which the output is stored */
+SDL_Surface *surface = SDL_CreateRGBSurface(0, screen.width, screen.height, 24, 0, 0, 0, 0);
+
+/* Set the uncorrected RGB pixels pointer of the conversion struct to that of the SDL pixel surface */
+amiVideo_setScreenUncorrectedRGBPixelsPointer(&screen, surface->pixels, surface->pitch, TRUE, surface->format->Rshift, surface->format->Gshift, surface->format->Bshift, surface->format->Ashift);
+
+/* Convert the bitplanes to RGB pixels */
+if(SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) != 0)
+{
+    fprintf(stderr, "Cannot lock the surface!\n");
+    return 1;
+}
+
+amiVideo_convertScreenBitplanesToRGBPixels(&screen);
+
+if(SDL_MUSTLOCK(surface))
+    SDL_UnlockSurface(surface);
+```
+
+Converting to corrected chunky pixels format
+--------------------------------------------
+For the previous output formats, every output pixel corresponds to a pixel in the
+original input format. However, as explained earlier, because of the different
+way pixels and scanlines are divided, we may observe odd results that we need to
+correct, for example by doubling the pixels or scanlines.
+
+The following example code converts a planar screen to a _corrected_ chunky
+surface:
+
+```C
+#include <SDL.h>
+
+SDL_Surface *surface;
+
+/*
+ * We set the size of a lowres pixel. A lowres pixel has the same size of
+ * two hires pixels. 2 will typically suffice for most images. To support
+ * super hires displays this value needs to be set to 4. However, this
+ * also results in a much bigger output picture.
+ */
+unsigned int lowresPixelScaleFactor = 2;
+amiVideo_setLowresPixelScaleFactor(&screen, lowresPixelScaleFactor);
+
+/*
+ * Create a SDL surface having 8 bits per pixel in which the output is stored.
+ * The correctedFormat sub struct provides us the dimensions of the corrected
+ * surface.
+ */
+surface = SDL_CreateRGBSurface(0, screen.correctedFormat.width, screen.correctedFormat.height, 8, 0, 0, 0, 0);
+
+/*
+ * Convert the colors of the palette from 4 bits per color component to 8
+ * bits per color component.
+ */
+amiVideo_convertBitplaneColorsToChunkyFormat(&screen.palette);
+
+/* Set the palette of the target SDL surface */
+if(SDL_SetPaletteColors(surface->format->palette, (SDL_Color*)screen.palette.chunkyFormat.color, 0, screen.palette.chunkyFormat.numOfColors) != 0)
+{
+    fprintf(stderr, "Cannot set palette of the surface!\n");
+    return 1;
+}
+
+/* Set the corrected chunky pixels pointer of the conversion struct to the SDL pixel surface */
+amiVideo_setScreenCorrectedPixelsPointer(&screen, surface->pixels, surface->pitch, 1, TRUE, 0, 0, 0, 0);
+
+/* Convert the bitplanes to corrected chunky pixels */
+if(SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) != 0)
+{
+    fprintf(stderr, "Cannot lock the surface!\n");
+    return 1;
+}
+
+amiVideo_convertScreenBitplanesToCorrectedChunkyPixels(&screen);
+
+if(SDL_MUSTLOCK(surface))
+    SDL_UnlockSurface(surface);
+```
+
+Converting to corrected RGB pixels format
+-----------------------------------------
+The following example code converts a planar screen to a corrected RGB surface:
+
+```C
+#include <SDL.h>
+
+SDL_Surface *surface;
+
+/*
+ * We set the size of a lowres pixel. A lowres pixel has the same size of
+ * two hires pixels. 2 will typically suffice for most images. To support
+ * super hires displays this value needs to be set to 4. However, this
+ * also results in a much bigger output picture.
+ */
+unsigned int lowresPixelScaleFactor = 2;
+amiVideo_setLowresPixelScaleFactor(&screen, lowresPixelScaleFactor);
+
+/*
+ * Create a SDL surface having 24 bits per pixel in which the output is
+ * stored. The correctedFormat sub struct provides us the dimensions of the
+ * corrected surface.
+ */
+surface = SDL_CreateRGBSurface(0, screen->correctedFormat.width, screen->correctedFormat.height, 24, 0, 0, 0, 0);
+
+/* Set the corrected RGB pixels pointer of the conversion struct to the SDL pixel surface */
+amiVideo_setScreenCorrectedPixelsPointer(&screen, surface->pixels, surface->pitch, 4, TRUE, surface->format->Rshift, surface->format->Gshift, surface->format->Bshift, surface->format->Ashift);
+
+/* Convert the bitplanes to corrected RGB pixels */
+if(SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) != 0)
+{
+    fprintf(stderr, "Cannot lock the surface!\n");
+    return 1;
+}
+
+amiVideo_convertScreenBitplanesToCorrectedRGBPixels(&screen);
+
+if(SDL_MUSTLOCK(surface))
+    SDL_UnlockSurface(surface);
+```
+
+Cleaning up the screen conversion struct
+----------------------------------------
+After conversions have been performed, we may remove the converstion struct's
+properties from memory:
+
+```C
+amiVideo_cleanupScreen(&screen);
+```
+
+Converting chunky graphics to planar graphics
+=============================================
+Apart from converting planar graphics to chunky or RGB format, we can also
+perform the opposite process -- converting graphics in chunky format to bitplanes
+so that a PC image can be displayed on a real Amiga with an OCS, ECS or AGA
+chipset.
+
+Acquiring a chunky graphics surface
+-----------------------------------
+In the examples used in the following subsections, we use the following
+imaginary struct representing a chunky graphics surface with a palette:
+
+```C
+struct
+{
+    UBYTE r, g, b, a;
+}
+Color;
+
+struct
+{
+    struct Color *colors;
+    unsigned int numOfColors;
+    int width, height;
+    void *pixels;
+}
+chunkyImage;
+```
+
+The above struct contains a palette with a specific amount of colors, a width
+(in pixels), height (in scanlines) and an array containing bytes representing
+chunky pixels.
+
+Creating a conversion struct instance
+-------------------------------------
+To convert the chunky image surface to a planar graphics surface, we must create
+an instance of the screen conversion struct taking the appropriate values of
+the chunky image:
+
+```C
+/* Create a screen conversion struct */
+amiVideo_Screen conversionScreen;
+
+/*
+ * Initialise a screen conversion struct. Chunky graphics normally have 8 bit
+ * color components and 256 colors.
+ */
+amiVideo_initScreen(&conversionScreen, chunkyImage.width, chunkyImage.height, 8, 8, 0);
+
+/* We must also set the colors of the viewport's chunky palette */
+amiVideo_setChunkyPaletteColors(&screen->palette, chunkyImage.colors, chunkyImage.numOfColors);
+
+/* Sets the uncorrected chunky pixels pointer of the conversion struct to that of the chunky pixel surface */
+amiVideo_setScreenUncorrectedChunkyPixelsPointer(conversionScreen, (amiVideo_UByte*)chunkyImage.pixels, chunkyImage.width);
+```
+
+After having configured the screen adapter, we can use it to convert the chunky
+pixel surface to something that can be displayed on Amiga hardware. In the next
+sections, we explain how this can be done.
+
+Creating a screen and setting the bitplane pointers
+---------------------------------------------------
+In this example, we will use the AmigaOS graphics and intuition APIs to create a
+custom intuition screen with the same dimensions and equivalent properties:
+
+```C
+#include <exec/types.h>
+
+#include <graphics/gfx.h>
+#include <intuition/intuition.h>
+
+#include <clib/graphics_protos.h>
+#include <clib/intuition_protos.h>
+
+/* Calculate a suitable viewport mode best suitable for displaying the image */
+ULONG viewportMode = amiVideo_calculateScreenViewportMode(&conversionScreen);
+
+/* Create an intuition screen */
+
+UWORD pens[] = { ~0 };
+
+struct TagItem screenTags[] = {
+    {SA_Width, conversionScreen.width },
+    {SA_Height, conversionScreen.height },
+    {SA_Depth, 8, /* VGA chunky graphics have 256 colors */
+    {SA_Title, "My converted picture"},
+    {SA_Pens, pens},
+    {SA_FullPalette, TRUE},
+    {SA_Type, CUSTOMSCREEN},
+    {SA_DisplayID, viewportMode},
+    {SA_AutoScroll, TRUE},
+    {TAG_DONE, NULL}
+};
+
+struct Screen *screen = OpenScreenTagList(NULL, screenTags);
+
+/* Set the bitplane pointers to those of the intuition screen */
+amiVideo_setScreenBitplanePointers(&conversionScreen, (amiVideo_UByte**)screen->ViewPort.RasInfo->BitMap->Planes);
+```
+
+Converting the palette
+----------------------
+The following example converts the colors of the chunky palette to the format
+of the bitplanes:
+
+```C
+/* Convert the palette */
+amiVideo_convertChunkyColorsToBitplaneFormat(&conversionScreen.palette);
+```
+
+Setting the palette colors for OCS/ECS chipsets
+-----------------------------------------------
+There are two ways to set a palette on AmigaOS. Each option uses a different
+color specification array.
+
+The most trivial is the format used by the `LoadRGB4()` function. This format can
+be generated as follows:
+
+```C
+/* Generate the color specification */
+amiVideo_UWord *colorSpecs = amiVideo_generateRGB4ColorSpecs(&conversionScreen);
+
+/* Set the palette using the generated color specification */
+LoadRGB4(screen->ViewPort, colorSpecs, conversionScreen.palette.bitplaneFormat.numOfColors);
+
+/* Remove the color specification from memory, since we don't need it anymore */
+free(colorSpecs);
+```
+
+The limitation of `LoadRGB4()` is that it can only set color values that have
+4-bit color components, preventing someone to use the more advanced AGA chipset's
+capabilities.
+
+Setting the palette colors for AGA chipsets
+-------------------------------------------
+The other format is used by the `LoadRGB32()` function and can be generated as
+follows:
+
+```C
+/* Generate the color specification */
+amiVideo_ULong *colorSpecs = amiVideo_generateRGB32ColorSpecs(&screen);
+
+/* Set the palette using the generated color specification */
+LoadRGB32(screen->ViewPort, colorSpecs);
+
+/* Remove the color specification from memory, since we don't need it anymore */
+free(colorSpecs);
+```
+
+The `LoadRGB32()` function can also be used to set colors with 8-bit color
+components.
+
+Converting chunky pixels to bitplanes
+-------------------------------------
+To convert the chunky pixels to bitplanes, we can do:
+
+```C
+/* Convert chunky pixels to bitplanes */
+amiVideo_convertScreenChunkyPixelsToBitplanes(&conversionScreen);
+```
+
+Cleaning up the screen conversion struct
+----------------------------------------
+After performing a conversion, we may remove the converstion struct's properties
+from memory once we don't need them anymore:
+
+```C
+amiVideo_cleanupScreen(&conversionScreen);
+```
+
+Miscellaneous functions
+=======================
+In the previous code examples, we have used various fixed values for certain
+properties. This library also provides a number of functions that can auto select
+them for you.
+
+Auto selecting a suitable color format
+--------------------------------------
+```C
+amiVideo_ColorFormat format;
+amiVideo_Screen screen;
+screen.viewportMode = AMIVIDEO_VIDEOPORTMODE_HAM;
+
+/* Returns AMIVIDEO_RGB_FORMAT */
+format = amiVideo_autoSelectColorFormat(&screen);
+```
+
+The above function invocation auto selects the most memory efficient color format
+for a given viewport mode. In the example, it returns AMIVIDEO_RGB_FORMAT since
+we have to display more than 256 colors.
+
+Auto selecting a lowres pixel scale factor
+------------------------------------------
+```C
+/* Returns 4 */
+amiVideo_autoSelectLowresPixelScaleFactor(AMIVIDEO_VIDEOPORTMODE_SUPERHIRES);
+```
+
+This function invocation auto selects the most memory efficient lowres pixel
+scale factor for a given viewport mode. The above example needs 4 bytes for a
+lowres pixel since super hires screens are at least 1280 pixels per scanline.
+
+Auto selecting a viewport mode
+------------------------------
+```C
+/* Returns AMIVIDEO_VIDEOPORTMODE_SUPERHIRES | AMIVIDEO_VIDEOPORTMODE_LACE */
+amiVideo_autoSelectViewportMode(1280, 512);
+```
+
+The above function invocation auto selects the best suitable resolution viewport
+mode bits for a screen with the given dimensions. To properly display an 1280x512
+image on an Amiga display, we have to use a interlaced screen with super hires
+resolution.
+
+Installation on Unix-like systems
+=================================
+Compilation and installation of this library on Unix-like systems is straight
+forward, by using the standard GNU autotools build instructions:
+
+    $ ./configure
+    $ make
+    $ make install
+
+More details about the installation process can be found in the `INSTALL` file
+included in this package.
+
+Building with Visual C++
+========================
+This package can also be built with Visual C++ for Windows platforms. The
+solution file resides in `src/libamivideo.sln` that can be used in Visual Studio
+to edit and build it.
+
+Alternatively, you can also build it with `MSBuild` from the command-line:
+
+    $ MSBuild libamivideo.sln
+
+The output is produced in the `Debug/` directory.
+
+License
+=======
+This library is available under the MIT license

+ 7 - 0
ilbm.mod/libamivideo/bootstrap

@@ -0,0 +1,7 @@
+#!/bin/sh
+
+rm -f config.cache config.log acconfig.h aclocal.m4 README
+
+ln -s README.md README
+mkdir -p config
+autoreconf -fvi

+ 20 - 0
ilbm.mod/libamivideo/configure.ac

@@ -0,0 +1,20 @@
+AC_PREREQ(2.61)
+AC_INIT([libamivideo], m4_esyscmd([echo -n $(cat ./version)$VERSION_SUFFIX]))
+AC_CONFIG_AUX_DIR([config])
+AM_INIT_AUTOMAKE([1.7.2 -Wall -Werror -Wno-extra-portability])
+
+# Checks for programs
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+AM_PROG_CC_C_O
+
+# Output
+AC_CONFIG_FILES([
+Makefile
+src/libamivideo.pc
+src/Makefile
+src/libamivideo/Makefile
+tests/Makefile
+])
+AC_OUTPUT

+ 78 - 0
ilbm.mod/libamivideo/release.nix

@@ -0,0 +1,78 @@
+{ nixpkgs ? <nixpkgs>
+, systems ? [ "i686-linux" "x86_64-linux" ]
+, buildForAmiga ? false
+, buildForWindows ? false
+, amigaosenvPath ? <amigaosenv>
+, kickstartROMFile ? null
+, baseDiskImage ? null
+, useUAE ? true
+, libamivideo ? {outPath = ./.; rev = 1234;}
+, officialRelease ? false
+}:
+
+let
+  pkgs = import nixpkgs {};
+  
+  version = builtins.readFile ./version;
+  
+  jobs = rec {
+    tarball =
+      with pkgs;
+
+      releaseTools.sourceTarball {
+        name = "libamivideo-tarball";
+        src = libamivideo;
+        inherit version officialRelease;
+
+        buildInputs = [];
+      };
+      
+    build =
+      (pkgs.lib.genAttrs systems (system:
+        with import nixpkgs { inherit system; };
+        
+        releaseTools.nixBuild {
+          name = "libamivideo";
+          inherit version;
+          src = tarball;
+          CFLAGS = "-ansi -pedantic -Wall";
+        }
+      )) //
+        (pkgs.lib.optionalAttrs (buildForWindows) { i686-windows =
+           pkgs.dotnetenv.buildSolution {
+             name = "libamivideo";
+             src = ./.;
+             baseDir = "src";
+             slnFile = "libamivideo.sln";
+             postInstall = ''
+               mkdir -p $out/include/libamivideo
+               cp -v libamivideo/*.h $out/include/libamivideo
+             '';
+           };
+        }) //
+      (pkgs.lib.optionalAttrs (buildForAmiga)
+        (let
+          amigaosenv = import amigaosenvPath {
+            inherit (pkgs) stdenv fetchurl lhasa uae fsuae procps bchunk cdrtools;
+            inherit (pkgs.xorg) lndir;
+          };
+        in
+        {
+          m68k-amigaos = amigaosenv.mkDerivation {
+            name = "libamivideo-${version}";
+            src = "${tarball}/tarballs/libamivideo-${version}pre1234.tar.gz";
+      
+            buildCommand = ''
+              tar xfvz $src
+              cd libamivideo-${version}pre1234
+              CFLAGS='-noixemul -O3' ./configure --prefix=/OUT --disable-shared
+              make
+              make check
+              make install
+            '';
+            inherit kickstartROMFile baseDiskImage useUAE;
+          };
+        }));
+  };
+in
+jobs

+ 1679 - 0
ilbm.mod/libamivideo/src/Doxyfile

@@ -0,0 +1,1679 @@
+# Doxyfile 1.7.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = libamivideo
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 0.1
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description for a project that appears at the top of each page and should give viewer a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ../doc/apidox
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = YES
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even if there is only one candidate or it is obvious which candidate to choose by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [0,1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+# Note that a value of 0 will completely suppress the enum values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, svg, gif or svg.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES

+ 9 - 0
ilbm.mod/libamivideo/src/Makefile.am

@@ -0,0 +1,9 @@
+SUBDIRS = libamivideo
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libamivideo.pc
+
+apidox:
+	doxygen Doxyfile
+
+EXTRA_DIST = libamivideo.pc.in

+ 11 - 0
ilbm.mod/libamivideo/src/libamivideo.pc.in

@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libamivideo
+Version: @VERSION@
+Description: Amiga (OCS/ECS/AGA) video format conversion library
+Requires:
+Libs: -L${libdir} -lamivideo
+Cflags: -I${includedir}

+ 22 - 0
ilbm.mod/libamivideo/src/libamivideo.sln

@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.21005.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libamivideo", "libamivideo\libamivideo.vcxproj", "{860901A5-A22B-404F-BDDB-0DB00A3A28EC}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{860901A5-A22B-404F-BDDB-0DB00A3A28EC}.Debug|Win32.ActiveCfg = Debug|Win32
+		{860901A5-A22B-404F-BDDB-0DB00A3A28EC}.Debug|Win32.Build.0 = Debug|Win32
+		{860901A5-A22B-404F-BDDB-0DB00A3A28EC}.Release|Win32.ActiveCfg = Release|Win32
+		{860901A5-A22B-404F-BDDB-0DB00A3A28EC}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 4 - 0
ilbm.mod/libamivideo/src/libamivideo/Makefile.am

@@ -0,0 +1,4 @@
+lib_LTLIBRARIES = libamivideo.la
+pkginclude_HEADERS = amivideotypes.h viewportmode.h palette.h screen.h
+
+libamivideo_la_SOURCES = viewportmode.c palette.c screen.c

+ 40 - 0
ilbm.mod/libamivideo/src/libamivideo/amivideotypes.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __AMIVIDEOTYPES_H
+#define __AMIVIDEOTYPES_H
+
+/** An unsigned byte */
+typedef unsigned char amiVideo_UByte;
+
+/** An unsigned word */
+typedef unsigned short amiVideo_UWord;
+
+/** An signed word */
+typedef unsigned short amiVideo_Word;
+
+/** A signed 4-bytes type */
+typedef int amiVideo_Long;
+
+/** An unsigned 4-bytes type */
+typedef unsigned int amiVideo_ULong;
+
+#endif

+ 40 - 0
ilbm.mod/libamivideo/src/libamivideo/libamivideo.def

@@ -0,0 +1,40 @@
+LIBRARY    libamivideo
+EXPORTS
+	amiVideo_initPalette                                   @1
+	amiVideo_cleanupPalette                                @2
+	amiVideo_setBitplanePaletteColors                      @3
+	amiVideo_setChunkyPaletteColors                        @4
+	amiVideo_convertBitplaneColorsToChunkyFormat           @5
+	amiVideo_convertChunkyColorsToBitplaneFormat           @6
+	amiVideo_generateRGB4ColorSpecs                        @7
+	amiVideo_generateRGB32ColorSpecs                       @8
+	amiVideo_initScreen                                    @9
+	amiVideo_createScreen                                  @10
+	amiVideo_cleanupScreen                                 @11
+	amiVideo_freeScreen                                    @12
+	amiVideo_calculateCorrectedWidth                       @13
+	amiVideo_calculateCorrectedHeight                      @14
+	amiVideo_setLowresPixelScaleFactor                     @15
+	amiVideo_setScreenBitplanePointers                     @16
+	amiVideo_setScreenBitplanes                            @17
+	amiVideo_setScreenUncorrectedChunkyPixelsPointer       @18
+	amiVideo_setScreenUncorrectedRGBPixelsPointer          @19
+	amiVideo_setScreenCorrectedPixelsPointer               @20
+	amiVideo_convertScreenBitplanesToChunkyPixels          @21
+	amiVideo_convertScreenChunkyPixelsToRGBPixels          @22
+	amiVideo_convertScreenChunkyPixelsToBitplanes          @23
+	amiVideo_correctScreenPixels                           @24
+	amiVideo_convertScreenBitplanesToRGBPixels             @25
+	amiVideo_convertScreenBitplanesToCorrectedChunkyPixels @26
+	amiVideo_convertScreenBitplanesToCorrectedRGBPixels    @27
+	amiVideo_convertScreenChunkyPixelsToCorrectedRGBPixels @28
+	amiVideo_checkExtraHalfbrite                           @29
+	amiVideo_checkHoldAndModify                            @30
+	amiVideo_checkHires                                    @31
+	amiVideo_checkSuperHires                               @32
+	amiVideo_checkLaced                                    @33
+	amiVideo_autoSelectColorFormat                         @34
+	amiVideo_autoSelectLowresPixelScaleFactor              @35
+	amiVideo_extractPaletteFlags                           @36
+	amiVideo_autoSelectViewportMode                        @37
+	amiVideo_reorderRGBPixels                              @38

+ 92 - 0
ilbm.mod/libamivideo/src/libamivideo/libamivideo.vcxproj

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{860901A5-A22B-404F-BDDB-0DB00A3A28EC}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBAMIVIDEO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <ModuleDefinitionFile>libamivideo.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBAMIVIDEO_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>libamivideo.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="palette.c" />
+    <ClCompile Include="screen.c" />
+    <ClCompile Include="viewportmode.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="amivideotypes.h" />
+    <ClInclude Include="palette.h" />
+    <ClInclude Include="screen.h" />
+    <ClInclude Include="viewportmode.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="libamivideo.def" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 47 - 0
ilbm.mod/libamivideo/src/libamivideo/libamivideo.vcxproj.filters

@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="palette.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="screen.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="viewportmode.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="amivideotypes.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="palette.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="screen.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="viewportmode.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="libamivideo.def">
+      <Filter>Source Files</Filter>
+    </None>
+  </ItemGroup>
+</Project>

+ 197 - 0
ilbm.mod/libamivideo/src/libamivideo/palette.c

@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "palette.h"
+#include <stdlib.h>
+#include <string.h>
+#include "viewportmode.h"
+
+static unsigned int determineNumOfColors(unsigned int bitplaneDepth)
+{
+    switch(bitplaneDepth)
+    {
+	case 1:
+	    return 2;
+	case 2:
+	    return 4;
+	case 3:
+	    return 8;
+	case 4:
+	    return 16;
+	case 5:
+	    return 32;
+	case 6:
+	    return 64;
+	case 7:
+	    return 128;
+	case 8:
+	    return 256;
+	default:
+	    return 0;
+    }
+}
+
+void amiVideo_initPalette(amiVideo_Palette *palette, unsigned int bitplaneDepth, unsigned int bitsPerColorChannel, amiVideo_Long viewportMode)
+{
+    /* Assign values */
+    palette->bitplaneFormat.viewportMode = viewportMode;
+    
+    /* Allocate memory for bitplane colors */
+
+    palette->bitplaneFormat.bitsPerColorChannel = bitsPerColorChannel;
+    palette->bitplaneFormat.numOfColors = determineNumOfColors(bitplaneDepth);
+    palette->bitplaneFormat.color = (amiVideo_Color*)malloc(palette->bitplaneFormat.numOfColors * sizeof(amiVideo_Color));
+
+    /* Allocate memory for chunky colors */
+    
+    if(amiVideo_checkExtraHalfbrite(viewportMode))
+        palette->chunkyFormat.numOfColors = 2 * palette->bitplaneFormat.numOfColors; /* Extra halfbrite screen mode has double the amount of colors */
+    else
+        palette->chunkyFormat.numOfColors = palette->bitplaneFormat.numOfColors;
+    
+    palette->chunkyFormat.color = (amiVideo_OutputColor*)malloc(palette->chunkyFormat.numOfColors * sizeof(amiVideo_OutputColor));
+}
+
+void amiVideo_cleanupPalette(amiVideo_Palette *palette)
+{
+    free(palette->bitplaneFormat.color);
+    free(palette->chunkyFormat.color);
+}
+
+void amiVideo_setBitplanePaletteColors(amiVideo_Palette *palette, amiVideo_Color *color, unsigned int numOfColors)
+{
+    unsigned int numOfRemainingColors = palette->bitplaneFormat.numOfColors - numOfColors;
+    
+    /* Copy the given colors */
+    memcpy(palette->bitplaneFormat.color, color, numOfColors * sizeof(amiVideo_Color));
+    
+    if(numOfRemainingColors > 0)
+	memset(palette->bitplaneFormat.color + numOfColors, '\0', numOfRemainingColors * sizeof(amiVideo_Color)); /* Set the remaining ones to 0 */
+}
+
+void amiVideo_setChunkyPaletteColors(amiVideo_Palette *palette, amiVideo_OutputColor *color, unsigned int numOfColors)
+{
+    unsigned int numOfRemainingColors = palette->chunkyFormat.numOfColors - numOfColors;
+    
+    /* Copy the given colors */
+    memcpy(palette->chunkyFormat.color, color, numOfColors * sizeof(amiVideo_OutputColor));
+    
+    if(numOfRemainingColors > 0)
+	memset(palette->chunkyFormat.color + numOfColors, '\0', numOfRemainingColors * sizeof(amiVideo_OutputColor)); /* Set the remaining ones to 0 */
+}
+
+void amiVideo_convertBitplaneColorsToChunkyFormat(amiVideo_Palette *palette)
+{
+    /* We must convert color channels that consist do not consist of 8 bits */
+    unsigned int i;
+    int shift = 8 - palette->bitplaneFormat.bitsPerColorChannel;
+
+    for(i = 0; i < palette->bitplaneFormat.numOfColors; i++)
+    {
+        amiVideo_Color *sourceColor = &palette->bitplaneFormat.color[i];
+        amiVideo_OutputColor *targetColor = &palette->chunkyFormat.color[i];
+
+        targetColor->r = sourceColor->r << shift;
+        targetColor->g = sourceColor->g << shift;
+        targetColor->b = sourceColor->b << shift;
+        targetColor->a = '\0';
+    }
+    
+    /* For extra half brite screen modes we must append half of the color values of the original color register values */
+    
+    if(amiVideo_checkExtraHalfbrite(palette->bitplaneFormat.viewportMode))
+    {
+	unsigned int i;
+	
+	for(i = 0; i < palette->bitplaneFormat.numOfColors; i++)
+	{
+	    amiVideo_OutputColor *sourceColor = &palette->chunkyFormat.color[i];
+	    amiVideo_OutputColor *targetColor = &palette->chunkyFormat.color[i + palette->bitplaneFormat.numOfColors];
+	    
+	    targetColor->r = sourceColor->r >> 1;
+	    targetColor->g = sourceColor->g >> 1;
+	    targetColor->b = sourceColor->b >> 1;
+	    targetColor->a = '\0';
+	}
+    }
+}
+
+void amiVideo_convertChunkyColorsToBitplaneFormat(amiVideo_Palette *palette)
+{
+    int shift = 8 - palette->bitplaneFormat.bitsPerColorChannel;
+    unsigned int i;
+    
+    for(i = 0; i < palette->bitplaneFormat.numOfColors; i++)
+    {
+	amiVideo_OutputColor chunkyColor = palette->chunkyFormat.color[i];
+	amiVideo_Color *color = &palette->bitplaneFormat.color[i];
+	
+	color->r = chunkyColor.r >> shift;
+	color->g = chunkyColor.g >> shift;
+	color->b = chunkyColor.g >> shift;
+    }
+}
+
+amiVideo_UWord *amiVideo_generateRGB4ColorSpecs(const amiVideo_Palette *palette)
+{
+    unsigned int i;
+    int shift = palette->bitplaneFormat.bitsPerColorChannel - 4;
+    amiVideo_UWord *colorSpecs = (amiVideo_UWord*)malloc(palette->bitplaneFormat.numOfColors * sizeof(amiVideo_UWord));
+    
+    for(i = 0; i < palette->bitplaneFormat.numOfColors; i++)
+    {
+	amiVideo_Color *color = &palette->bitplaneFormat.color[i];
+	colorSpecs[i] = ((color->r >> shift) << 8) | ((color->g >> shift) << 4) | (color->b >> shift);
+    }
+    
+    return colorSpecs;
+}
+
+amiVideo_ULong *amiVideo_generateRGB32ColorSpecs(const amiVideo_Palette *palette)
+{
+    unsigned int i;
+    unsigned int index = 1;
+    int shift = 32 - palette->bitplaneFormat.bitsPerColorChannel;
+    
+    amiVideo_ULong *colorSpecs = (amiVideo_ULong*)malloc((palette->bitplaneFormat.numOfColors * 3 + 2) * sizeof(amiVideo_ULong));
+    
+    /* First element's first word is number of colors, second word is the first color to be loaded (which is 0) */
+    colorSpecs[0] = palette->bitplaneFormat.numOfColors << 16;
+    
+    /* Remaining elements are red, green, blue component values for each color register */
+    for(i = 0; i < palette->bitplaneFormat.numOfColors; i++)
+    {
+	amiVideo_Color color = palette->bitplaneFormat.color[i];
+	
+	colorSpecs[index] = color.r << shift;
+	index++;
+	colorSpecs[index] = color.g << shift;
+	index++;
+	colorSpecs[index] = color.b << shift;
+	index++;
+    }
+    
+    /* Add 0 termination at the end */
+    colorSpecs[index] = 0;
+    
+    /* Return the generated color specs */
+    return colorSpecs;
+}

+ 178 - 0
ilbm.mod/libamivideo/src/libamivideo/palette.h

@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __AMIVIDEO_PALETTE_H
+#define __AMIVIDEO_PALETTE_H
+#include "amivideotypes.h"
+
+/**
+ * @brief Struct storing values of a color channel.
+ */
+typedef struct
+{
+    /** Defines the intensity of the red color channel */
+    amiVideo_UByte r;
+    
+    /** Defines the intensity of the green color channel */
+    amiVideo_UByte g;
+    
+    /** Defines the intensity of the blue color channel */
+    amiVideo_UByte b;
+}
+amiVideo_Color;
+
+/**
+ * @brief Struct storing values of a color channel.
+ * This struct type has the same structure as the SDL_Color struct.
+ */
+typedef struct
+{
+    /** Defines the intensity of the red color channel */
+    amiVideo_UByte r;
+    
+    /** Defines the intensity of the green color channel */
+    amiVideo_UByte g;
+    
+    /** Defines the intensity of the blue color channel */
+    amiVideo_UByte b;
+
+    /** Defines the intensity of the alpha color channel */
+    amiVideo_UByte a;
+}
+amiVideo_OutputColor;
+
+typedef struct
+{
+    struct
+    {
+	/** Contains the viewport mode settings */
+	amiVideo_Long viewportMode;
+        
+	/** Contains the number of colors in the original Amiga palette */
+	unsigned int numOfColors;
+	
+	/** Stores the color values of the palette */
+	amiVideo_Color *color;
+	
+	/** Contains the number of bits that a color component has (4 = OCS/ECS, 8 = AGA) */
+	unsigned int bitsPerColorChannel;
+    }
+    bitplaneFormat;
+    
+    struct
+    {
+	/** Contains the number of colors in the converted chunky graphics palette */
+	unsigned int numOfColors;
+	
+	/** Stores the color values of the palette */
+	amiVideo_OutputColor *color;
+    }
+    chunkyFormat;
+}
+amiVideo_Palette;
+
+/**
+ * Initialises the palette with the given bitplane depth, bits per color channel
+ * and viewport mode.
+ *
+ * @param palette Palette conversion structure
+ * @param bitplaneDepth Bitplane depth, a value between 1-6 (OCS/ECS) and 1-8 (AGA)
+ * @param bitsPerColorChannel The amount of bits for used for a color component (4 = ECS/OCS, 8 = AGA)
+ * @param viewportMode The viewport mode value
+ */
+void amiVideo_initPalette(amiVideo_Palette *palette, unsigned int bitplaneDepth, unsigned int bitsPerColorChannel, amiVideo_Long viewportMode);
+
+/**
+ * Frees all the heap allocated members of the palette from memory.
+ *
+ * @param palette Palette conversion structure
+ */
+void amiVideo_cleanupPalette(amiVideo_Palette *palette);
+
+/**
+ * Sets the palette's bitplane color values to the values in a given array. The
+ * remaining colors are set to 0. The color values must be in the Amiga screen's
+ * format, i.e. 4 bits or 8 bits per pixel.
+ *
+ * @param palette Palette conversion structure
+ * @param color Array of color values
+ * @param numOfColors The amount of colors in the color value array
+ */
+void amiVideo_setBitplanePaletteColors(amiVideo_Palette *palette, amiVideo_Color *color, unsigned int numOfColors);
+
+/**
+ * Sets the palette's chunky color values to the values in a given array. The
+ * remaining colors are set to 0. The color values must be in the chunky screen
+ * format, i.e. 8 bits per pixel.
+ *
+ * @param palette Palette conversion structure
+ * @param color Array of color values
+ * @param numOfColors The amount of colors in the color value array
+ */
+void amiVideo_setChunkyPaletteColors(amiVideo_Palette *palette, amiVideo_OutputColor *color, unsigned int numOfColors);
+
+/**
+ * Converts the original palette used for the bitplanes to the ones used for
+ * displaying chunky graphics. This means that a palette in which the color
+ * components consist 4 bits are converted to 8 bits.
+ *
+ * If the viewportMode has the extra halfbrite bit set, then the amount of
+ * colors are doubled in which the color values of latter half, are half of the
+ * values of the first half of the palette.
+ *
+ * @param palette Palette conversion structure
+ */
+void amiVideo_convertBitplaneColorsToChunkyFormat(amiVideo_Palette *palette);
+
+/**
+ * Converts the palette used for chunky graphics to a format that can be for
+ * displaying bitplanes. If an palette with 4 bit color components is used,
+ * then the color components are shifted.
+ *
+ * @param palette Palette conversion structure
+ */
+void amiVideo_convertChunkyColorsToBitplaneFormat(amiVideo_Palette *palette);
+
+/**
+ * Converts the bitplane palette to an array of word specifications, which can
+ * be used by AmigaOS' LoadRGB4() function to set a screen's palette. This
+ * function does not support the AGA chipset's capabilities. The resulting array
+ * has as many elements as the bitplane palette and is allocated on the heap.
+ * Therefore, free() must be invoked when it has become obsolete.
+ *
+ * @param palette Palette conversion structure
+ * @return A word array containing the color specifications for the LoadRGB4() function.
+ */
+amiVideo_UWord *amiVideo_generateRGB4ColorSpecs(const amiVideo_Palette *palette);
+
+/**
+ * Converts the bitplane palette to an array of long integer color
+ * specifications, which can be used by AmigaOS' LoadRGB32() function to set a
+ * screen's palette. To use the AGA chipset's abilities, it's required to use
+ * this function. The resulting array is allocated on the heap and must be
+ * deleted with free() when it has become obsolete.
+ *
+ * @param palette Palette conversion structure
+ * @return An long integer array containing the color specifications for the LoadRGB32() function.
+ */
+amiVideo_ULong *amiVideo_generateRGB32ColorSpecs(const amiVideo_Palette *palette);
+
+#endif

+ 457 - 0
ilbm.mod/libamivideo/src/libamivideo/screen.c

@@ -0,0 +1,457 @@
+#include "screen.h"
+#include <stdlib.h>
+#include <string.h>
+#include "viewportmode.h"
+
+#define TRUE 1
+#define FALSE 0
+
+void amiVideo_initScreen(amiVideo_Screen *screen, amiVideo_Word width, amiVideo_Word height, unsigned int bitplaneDepth, unsigned int bitsPerColorChannel, amiVideo_Long viewportMode)
+{
+    unsigned int scanLineSizeInWords;
+
+    /* Assign values */
+    screen->width = width;
+    screen->height = height;
+    screen->bitplaneDepth = bitplaneDepth;
+    screen->viewportMode = viewportMode;
+    
+    /* Set allocation bits to FALSE */
+    screen->bitplaneFormat.memoryAllocated = FALSE;
+    screen->uncorrectedChunkyFormat.memoryAllocated = FALSE;
+    screen->uncorrectedRGBFormat.memoryAllocated = FALSE;
+    
+    /* Sets the palette */
+    amiVideo_initPalette(&screen->palette, bitplaneDepth, bitsPerColorChannel, viewportMode);
+    
+    /* Calculate the pitch of the bitplanes. The width in bytes is rounded to the nearest word boundary */
+    
+    scanLineSizeInWords = screen->width / 16;
+    
+    if(screen->width % 16 != 0)
+        scanLineSizeInWords++;
+
+    screen->bitplaneFormat.pitch = scanLineSizeInWords * 2;
+}
+
+amiVideo_Screen *amiVideo_createScreen(amiVideo_Word width, amiVideo_Word height, unsigned int bitplaneDepth, unsigned int bitsPerColorChannel, amiVideo_Long viewportMode)
+{
+    amiVideo_Screen *screen = (amiVideo_Screen*)malloc(sizeof(amiVideo_Screen));
+    
+    if(screen != NULL)
+	amiVideo_initScreen(screen, width, height, bitplaneDepth, bitsPerColorChannel, viewportMode);
+    
+    /* Return the allocated screen */
+    return screen;
+}
+
+void amiVideo_cleanupScreen(amiVideo_Screen *screen)
+{
+    amiVideo_cleanupPalette(&screen->palette);
+
+    if(screen->uncorrectedChunkyFormat.memoryAllocated)
+	free(screen->uncorrectedChunkyFormat.pixels);
+    
+    if(screen->uncorrectedRGBFormat.memoryAllocated)
+	free(screen->uncorrectedRGBFormat.pixels);
+}
+
+void amiVideo_freeScreen(amiVideo_Screen *screen)
+{
+    amiVideo_cleanupScreen(screen);
+    free(screen);
+}
+
+int amiVideo_calculateCorrectedWidth(unsigned int lowresPixelScaleFactor, amiVideo_Long width, amiVideo_Long viewportMode)
+{
+    if(amiVideo_checkSuperHires(viewportMode))
+        return lowresPixelScaleFactor * width / 4;
+    else if(amiVideo_checkHires(viewportMode))
+        return lowresPixelScaleFactor * width / 2; /* Hires pixels have double the size of super hires pixels */
+    else
+        return lowresPixelScaleFactor * width; /* Lowres pixels have double the size of hi-res pixels */
+}
+
+int amiVideo_calculateCorrectedHeight(unsigned int lowresPixelScaleFactor, amiVideo_Long height, amiVideo_Long viewportMode)
+{
+    if(amiVideo_checkLaced(viewportMode))
+        return lowresPixelScaleFactor * height / 2;
+    else
+        return lowresPixelScaleFactor * height; /* Non-interlaced screens have double the amount of scanlines */
+}
+
+void amiVideo_setLowresPixelScaleFactor(amiVideo_Screen *screen, unsigned int lowresPixelScaleFactor)
+{
+    screen->correctedFormat.lowresPixelScaleFactor = lowresPixelScaleFactor;
+    
+    screen->correctedFormat.width = amiVideo_calculateCorrectedWidth(lowresPixelScaleFactor, screen->width, screen->viewportMode);
+    screen->correctedFormat.height = amiVideo_calculateCorrectedHeight(lowresPixelScaleFactor, screen->height, screen->viewportMode);
+}
+
+void amiVideo_setScreenBitplanePointers(amiVideo_Screen *screen, amiVideo_UByte **bitplanes)
+{
+    memcpy(screen->bitplaneFormat.bitplanes, bitplanes, screen->bitplaneDepth * sizeof(amiVideo_UByte*));
+}
+
+void amiVideo_setScreenBitplanes(amiVideo_Screen *screen, amiVideo_UByte *bitplanes)
+{
+    amiVideo_UByte *bitplanePointers[AMIVIDEO_MAX_NUM_OF_BITPLANES];
+    unsigned int offset = 0;
+    unsigned int i;
+    
+    /* Set bitplane pointers */
+    
+    for(i = 0; i < screen->bitplaneDepth; i++)
+    {
+	bitplanePointers[i] = bitplanes + offset;
+	offset += screen->bitplaneFormat.pitch * screen->height;
+    }
+    
+    /* Set bitplane pointers */
+    amiVideo_setScreenBitplanePointers(screen, bitplanePointers);
+}
+
+void amiVideo_setScreenUncorrectedChunkyPixelsPointer(amiVideo_Screen *screen, amiVideo_UByte *pixels, unsigned int pitch)
+{
+    screen->uncorrectedChunkyFormat.pixels = pixels;
+    screen->uncorrectedChunkyFormat.pitch = pitch;
+    screen->uncorrectedChunkyFormat.memoryAllocated = FALSE;
+}
+
+void amiVideo_setScreenUncorrectedRGBPixelsPointer(amiVideo_Screen *screen, amiVideo_ULong *pixels, unsigned int pitch, int allocateUncorrectedMemory, amiVideo_UByte rshift, amiVideo_UByte gshift, amiVideo_UByte bshift, amiVideo_UByte ashift)
+{
+    screen->uncorrectedRGBFormat.pixels = pixels;
+    screen->uncorrectedRGBFormat.pitch = pitch;
+    screen->uncorrectedRGBFormat.memoryAllocated = FALSE;
+    screen->uncorrectedRGBFormat.rshift = rshift;
+    screen->uncorrectedRGBFormat.gshift = gshift;
+    screen->uncorrectedRGBFormat.bshift = bshift;
+    screen->uncorrectedRGBFormat.ashift = ashift;
+    
+    if(allocateUncorrectedMemory)
+    {
+	screen->uncorrectedChunkyFormat.pitch = screen->width;
+	screen->uncorrectedChunkyFormat.pixels = (amiVideo_UByte*)calloc(screen->uncorrectedChunkyFormat.pitch * screen->height, sizeof(amiVideo_UByte));
+	screen->uncorrectedChunkyFormat.memoryAllocated = TRUE;
+    }
+}
+
+void amiVideo_setScreenCorrectedPixelsPointer(amiVideo_Screen *screen, void *pixels, unsigned int pitch, unsigned int bytesPerPixel, int allocateUncorrectedMemory, amiVideo_UByte rshift, amiVideo_UByte gshift, amiVideo_UByte bshift, amiVideo_UByte ashift)
+{
+    screen->correctedFormat.pixels = pixels;
+    screen->correctedFormat.pitch = pitch;
+    screen->correctedFormat.bytesPerPixel = bytesPerPixel;
+    
+    if(allocateUncorrectedMemory)
+    {
+	screen->uncorrectedChunkyFormat.pitch = screen->width;
+	screen->uncorrectedChunkyFormat.pixels = (amiVideo_UByte*)calloc(screen->uncorrectedChunkyFormat.pitch * screen->height, sizeof(amiVideo_UByte));
+	screen->uncorrectedChunkyFormat.memoryAllocated = TRUE;
+	
+	if(bytesPerPixel == 4)
+	{
+	    screen->uncorrectedRGBFormat.pitch = screen->width * 4;
+	    screen->uncorrectedRGBFormat.pixels = (amiVideo_ULong*)calloc(screen->uncorrectedRGBFormat.pitch * screen->height, sizeof(amiVideo_UByte));
+	    screen->uncorrectedRGBFormat.memoryAllocated = TRUE;
+	    screen->uncorrectedRGBFormat.rshift = rshift;
+	    screen->uncorrectedRGBFormat.gshift = gshift;
+	    screen->uncorrectedRGBFormat.bshift = bshift;
+	    screen->uncorrectedRGBFormat.ashift = ashift;
+	}
+	else
+	    screen->uncorrectedRGBFormat.memoryAllocated = FALSE;
+    }
+    else
+    {
+	screen->uncorrectedChunkyFormat.memoryAllocated = FALSE;
+	screen->uncorrectedRGBFormat.memoryAllocated = FALSE;
+    }
+}
+
+static void convertScreenBitplanesToTarget(amiVideo_Screen *screen, int chunky)
+{
+    unsigned int i;
+    
+    for(i = 0; i < screen->bitplaneDepth; i++) /* Iterate over each bitplane */
+    {
+	unsigned int count = 0;
+	amiVideo_ULong indexBit = 1 << i;
+	amiVideo_UByte *bitplanes = screen->bitplaneFormat.bitplanes[i];
+	unsigned int vOffset = 0;
+	unsigned int j;
+	
+	for(j = 0; j < screen->height; j++) /* Iterate over each scan line */
+	{
+	    unsigned int hOffset = vOffset;
+	    unsigned int k;
+	    unsigned int pixelCount = 0;
+	    
+	    for(k = 0; k < screen->bitplaneFormat.pitch; k++) /* Iterate over each byte containing 8 pixels */
+	    {
+		amiVideo_UByte bitplane = bitplanes[hOffset];
+		unsigned char bitmask = 0x80;
+		unsigned int l;
+		
+		for(l = 0; l < 8; l++) /* Iterate over each bit representing a pixel */
+		{
+		    if(pixelCount < screen->width) /* We must skip the padding bits. If we have already converted sufficient pixels on this scanline, ignore the rest */
+		    {
+			if(bitplane & bitmask)
+			{
+			    if(chunky)
+			        screen->uncorrectedChunkyFormat.pixels[count] |= indexBit;
+			    else
+			        screen->uncorrectedRGBFormat.pixels[count] |= indexBit;
+			}
+			count++;
+		    }
+		    
+		    pixelCount++;
+		    bitmask >>= 1;
+		}
+		
+		hOffset++;
+	    }
+	    
+	    /* Skip the padding bytes in the output */
+	    if(chunky)
+	        count += screen->uncorrectedChunkyFormat.pitch - screen->width; 
+	    else
+	        count += screen->uncorrectedRGBFormat.pitch / 4 - screen->width; 
+	    
+	    vOffset += screen->bitplaneFormat.pitch;
+	}
+    }
+}
+
+void amiVideo_convertScreenBitplanesToChunkyPixels(amiVideo_Screen *screen)
+{
+    convertScreenBitplanesToTarget(screen, TRUE);
+}
+
+static amiVideo_ULong convertColorToRGBPixel(const amiVideo_OutputColor *color, amiVideo_UByte rshift, amiVideo_UByte gshift, amiVideo_UByte bshift, amiVideo_UByte ashift)
+{
+    return (color->r << rshift) | (color->g << gshift) | (color->b << bshift) | (color->a << ashift);
+}
+
+void amiVideo_convertScreenChunkyPixelsToRGBPixels(amiVideo_Screen *screen)
+{
+    unsigned int screenWidthInPixels = screen->uncorrectedRGBFormat.pitch / 4;
+    
+    if(amiVideo_checkHoldAndModify(screen->viewportMode))
+    {
+	/* HAM mode has its own decompression technique */
+	
+	unsigned int i;
+	unsigned int offset = 0;
+	
+	for(i = 0; i < screen->height; i++)
+	{
+	    unsigned int j;
+	    amiVideo_OutputColor previousResult = screen->palette.chunkyFormat.color[0];
+	    
+	    for(j = 0; j < screenWidthInPixels; j++)
+	    {
+		amiVideo_UByte byte = screen->uncorrectedChunkyFormat.pixels[offset + j];
+		amiVideo_UByte mode = (byte & (0x3 << (screen->bitplaneDepth - 2))) >> (screen->bitplaneDepth - 2);
+		amiVideo_UByte index = byte & ~(0x3 << (screen->bitplaneDepth - 2));
+		amiVideo_OutputColor result;
+		
+		if(mode == 0x0) /* Data bits are an index in the color palette */
+		    result = screen->palette.chunkyFormat.color[index];
+		else if(mode == 0x1) /* Data bits are blue level */
+		{
+		    result = previousResult;
+		    result.b = index << (8 - screen->bitplaneDepth + 2);
+		}
+		else if(mode == 0x2) /* Data bits are red level */
+		{
+		    result = previousResult;
+		    result.r = index << (8 - screen->bitplaneDepth + 2);
+		}
+		else if(mode == 0x3) /* Data bits are green level */
+		{
+		    result = previousResult;
+		    result.g = index << (8 - screen->bitplaneDepth + 2);
+		}
+		
+		/* set new pixel on offset + j */
+		screen->uncorrectedRGBFormat.pixels[offset + j] = convertColorToRGBPixel(&result, screen->uncorrectedRGBFormat.rshift, screen->uncorrectedRGBFormat.gshift, screen->uncorrectedRGBFormat.bshift, screen->uncorrectedRGBFormat.ashift);
+		
+		previousResult = result;
+	    }
+	    
+	    offset += screenWidthInPixels;
+	}
+    }
+    else
+    {
+	/* Normal mode */
+	
+	unsigned int i;
+	
+	for(i = 0; i < screenWidthInPixels * screen->height; i++)
+	    screen->uncorrectedRGBFormat.pixels[i] = convertColorToRGBPixel(&screen->palette.chunkyFormat.color[screen->uncorrectedChunkyFormat.pixels[i]], screen->uncorrectedRGBFormat.rshift, screen->uncorrectedRGBFormat.gshift, screen->uncorrectedRGBFormat.bshift, screen->uncorrectedRGBFormat.ashift);
+    }
+}
+
+void amiVideo_convertScreenChunkyPixelsToBitplanes(amiVideo_Screen *screen)
+{
+    unsigned int i;
+    unsigned int bitplaneIndex = 0;
+    int bit = 7;
+    
+    for(i = 0; i < screen->width * screen->height; i++)
+    {
+	unsigned int j;
+	amiVideo_UByte bitmask = 1 << bit;
+	
+	for(j = 0; j < screen->bitplaneDepth; j++)
+	{
+	    if(screen->uncorrectedChunkyFormat.pixels[i] & (1 << j)) /* Check if the current bit of the index value is set */
+		screen->bitplaneFormat.bitplanes[j][bitplaneIndex] |= bitmask; /* Modify the current bit in the bitplane byte to be 1 and leave the others untouched */
+	    else
+		screen->bitplaneFormat.bitplanes[j][bitplaneIndex] &= ~bitmask; /* Modify the current bit in the bitplane byte to be 0 and leave the others untouched */
+	}
+	
+	bit--;
+	
+	if(bit < 0)
+	{
+	    bit = 7; /* Reset the bit counter */
+	    bitplaneIndex++; /* Go to the next byte in the bitplane memory */
+	}
+    }
+}
+
+void amiVideo_correctScreenPixels(amiVideo_Screen *screen)
+{
+    unsigned int i;
+    unsigned int sourceOffset = 0, destOffset = 0;
+    
+    unsigned int repeatHorizontal;
+    unsigned int repeatVertical;
+    
+    amiVideo_UByte *pixels;
+    
+    /* Calculate how many times we have to horizontally repeat a pixel */
+    if(amiVideo_checkSuperHires(screen->viewportMode))
+	repeatHorizontal = screen->correctedFormat.lowresPixelScaleFactor / 4;
+    else if(amiVideo_checkHires(screen->viewportMode))
+        repeatHorizontal = screen->correctedFormat.lowresPixelScaleFactor / 2;
+    else
+        repeatHorizontal = screen->correctedFormat.lowresPixelScaleFactor;
+    
+    /* Calculate how many times we have to vertically repeat a scanline */
+    
+    if(amiVideo_checkLaced(screen->viewportMode))
+        repeatVertical = screen->correctedFormat.lowresPixelScaleFactor / 2;
+    else
+        repeatVertical = screen->correctedFormat.lowresPixelScaleFactor;
+    
+    /* Check which pixels we have to correct */
+    
+    if(screen->correctedFormat.bytesPerPixel == 1)
+	pixels = screen->uncorrectedChunkyFormat.pixels;
+    else
+	pixels = (amiVideo_UByte*)screen->uncorrectedRGBFormat.pixels;
+    
+    /* Do the correction */
+    for(i = 0; i < screen->height; i++)
+    {
+	unsigned int j;
+	
+	for(j = 0; j < screen->width; j++)
+	{
+	    unsigned int k;
+	    
+	    /* Scale the pixel horizontally */
+	    for(k = 0; k < repeatHorizontal; k++)
+	    {
+	        memcpy((amiVideo_UByte*)screen->correctedFormat.pixels + destOffset, pixels + sourceOffset, screen->correctedFormat.bytesPerPixel);
+	        destOffset += screen->correctedFormat.bytesPerPixel;
+	    }
+	
+	    sourceOffset += screen->correctedFormat.bytesPerPixel;
+	}
+	
+	destOffset += screen->correctedFormat.pitch - screen->correctedFormat.width * screen->correctedFormat.bytesPerPixel; /* Skip the padding bytes */
+	
+	/* Non-interlace screen scanlines must be doubled */
+	
+	for(j = 1; j < repeatVertical; j++)
+	{
+	    memcpy((amiVideo_UByte*)screen->correctedFormat.pixels + destOffset, (amiVideo_UByte*)screen->correctedFormat.pixels + destOffset - screen->correctedFormat.pitch, screen->correctedFormat.pitch);
+	    destOffset += screen->correctedFormat.pitch;
+	}
+    }
+}
+
+void amiVideo_convertScreenBitplanesToRGBPixels(amiVideo_Screen *screen)
+{
+    if(screen->bitplaneDepth == 24 || screen->bitplaneDepth == 32) /* For true color images we directly convert bitplanes to RGB pixels */
+    {
+        convertScreenBitplanesToTarget(screen, FALSE);
+        amiVideo_reorderRGBPixels(screen);
+    }
+    else
+    {
+        /* For lower bitplane depths we first have to compose chunky pixels to determine the actual color values */
+        amiVideo_convertBitplaneColorsToChunkyFormat(&screen->palette);
+        amiVideo_convertScreenBitplanesToChunkyPixels(screen);
+        amiVideo_convertScreenChunkyPixelsToRGBPixels(screen);
+    }
+}
+
+void amiVideo_convertScreenBitplanesToCorrectedChunkyPixels(amiVideo_Screen *screen)
+{
+    amiVideo_convertScreenBitplanesToChunkyPixels(screen);
+    amiVideo_correctScreenPixels(screen);
+}
+
+void amiVideo_convertScreenBitplanesToCorrectedRGBPixels(amiVideo_Screen *screen)
+{
+    amiVideo_convertScreenBitplanesToRGBPixels(screen);
+    amiVideo_correctScreenPixels(screen);
+}
+
+void amiVideo_convertScreenChunkyPixelsToCorrectedRGBPixels(amiVideo_Screen *screen)
+{
+    amiVideo_convertScreenChunkyPixelsToRGBPixels(screen);
+    amiVideo_correctScreenPixels(screen);
+}
+
+amiVideo_ColorFormat amiVideo_autoSelectColorFormat(const amiVideo_Screen *screen)
+{
+    if(amiVideo_checkHoldAndModify(screen->viewportMode) || screen->bitplaneDepth == 24 || screen->bitplaneDepth == 32)
+        return AMIVIDEO_RGB_FORMAT;
+    else
+        return AMIVIDEO_CHUNKY_FORMAT;
+}
+
+static void reorderPixelBytes(amiVideo_Screen *screen, amiVideo_UByte rshift, amiVideo_UByte gshift, amiVideo_UByte bshift, amiVideo_UByte ashift)
+{
+    unsigned int i;
+    
+    for(i = 0; i < screen->uncorrectedRGBFormat.pitch / 4 * screen->height; i++)
+    {
+        amiVideo_ULong pixel = screen->uncorrectedRGBFormat.pixels[i];
+        amiVideo_OutputColor color;
+        
+        color.r = (pixel >> rshift) & 0xff;
+        color.g = (pixel >> gshift) & 0xff;
+        color.b = (pixel >> bshift) & 0xff;
+        color.a = (pixel >> ashift) & 0xff;
+        
+        convertColorToRGBPixel(&color, screen->uncorrectedRGBFormat.rshift, screen->uncorrectedRGBFormat.gshift, screen->uncorrectedRGBFormat.bshift, screen->uncorrectedRGBFormat.ashift);
+    }
+}
+
+void amiVideo_reorderRGBPixels(amiVideo_Screen *screen)
+{
+    /* Reorder the bytes if the real display uses a different order */
+    if(screen->bitplaneDepth == 24 && (screen->uncorrectedRGBFormat.ashift != 24 || screen->uncorrectedRGBFormat.rshift != 16 || screen->uncorrectedRGBFormat.gshift != 8 || screen->uncorrectedRGBFormat.bshift != 0))
+        reorderPixelBytes(screen, 16, 8, 0, 24);
+    else if(screen->bitplaneDepth == 32 && (screen->uncorrectedRGBFormat.rshift != 24 || screen->uncorrectedRGBFormat.gshift != 16 || screen->uncorrectedRGBFormat.bshift != 8 || screen->uncorrectedRGBFormat.ashift != 0))
+        reorderPixelBytes(screen, 24, 16, 8, 0);
+}

+ 365 - 0
ilbm.mod/libamivideo/src/libamivideo/screen.h

@@ -0,0 +1,365 @@
+#ifndef __AMIVIDEO_SCREEN_H
+#define __AMIVIDEO_SCREEN_H
+
+#define AMIVIDEO_MAX_NUM_OF_BITPLANES 32
+
+#include "amivideotypes.h"
+#include "palette.h"
+
+typedef struct amiVideo_Screen amiVideo_Screen;
+
+/**
+ * A data structure representing an Amiga screen (or viewport) containing
+ * conversion sub structures that store the screen in a different displaying
+ * format.
+ */
+struct amiVideo_Screen
+{
+    /** Defines the width of the screen in pixels */
+    amiVideo_Word width;
+    
+    /** Defines the height of the screen in pixels */
+    amiVideo_Word height;
+    
+    /** Defines the bitplane depth */
+    unsigned int bitplaneDepth;
+    
+    /** Contains the viewport mode settings */
+    amiVideo_Long viewportMode;
+    
+    /* Contains the values of the color registers and its converted values */
+    amiVideo_Palette palette;
+    
+    /**
+     * Contains all the relevant properties of the current screen to display it
+     * in planar format -- the format that Amiga's OCS, ECS and AGA chipsets use.
+     * In this format, each bit represents a part of the palette index of a pixel
+     * and is stored the amount bitplanes times in memory.
+     *
+     * For example, a screen with 32 colors has a bitplane depth of 5. In this
+     * case the pixels are stored five times in memory in which each bit of a
+     * plane represents a pixel.
+     * 
+     * The bits in first occurence of the bitplane represent the most significant
+     * bit and the last the least significant bit of the pixel's index value.
+     * By combining all these bits from the most significant bit to the least
+     * significant bit we will get the index value of the palette of the pixel.
+     *
+     * Widths are padded till the nearest word boundary (i.e. multiples of 16).
+     */
+    struct
+    {
+	/** Contains pointers to each bitplane section that stores parts of each pixel's color component */
+	amiVideo_UByte *bitplanes[AMIVIDEO_MAX_NUM_OF_BITPLANES];
+	
+	/** Contains the padded width in pixels that is rounded up to the nearest word boundary */
+	unsigned int pitch;
+	
+	/** Indicates whether the pixel memory is allocated and needs to be freed */
+	int memoryAllocated;
+    }
+    bitplaneFormat;
+    
+    /**
+     * Contains all the relevant properties of the current screen to display it
+     * in chunky format -- used by PC displays with 256 colors. In this format,
+     * each byte represents a pixel in which the value refers to an index in the
+     * palette.
+     *
+     * The screen width may be padded.
+     */
+    struct
+    {
+	/** Contains the padded screen width in bytes */
+	unsigned int pitch;
+	
+	/** Contains the pixel data in which each byte represents an index in the palette */
+	amiVideo_UByte *pixels;
+	
+	/** Indicates whether the pixel memory is allocated and needs to be freed */
+	int memoryAllocated;
+    }
+    uncorrectedChunkyFormat;
+    
+    /** 
+     * Contains all the relevant properties of the current screen to display it
+     * in RGB format in which every four bytes represent the red, green, blue
+     * value of a pixel and a padding byte.
+     *
+     * The screen width may be padded.
+     */
+    struct
+    {
+	/** Contains the padded screen width in bytes (usually rounded up to the nearest 4-byte boundary) */
+	unsigned int pitch;
+	
+	/** Contains the amount of bits that we have to left shift the red color component */
+	amiVideo_UByte rshift;
+	
+	/** Contains the amount of bits that we have to left shift the green color component */
+	amiVideo_UByte gshift;
+	
+	/** Contains the amount of bits that we have to left shift the blue color component */
+	amiVideo_UByte bshift;
+	
+	/** Contains the amount of bits that we have to left shift the alpha color component */
+	amiVideo_UByte ashift;
+	
+	/** Contains the pixel data in which each four bytes represent red, glue, blue values and a padding byte */
+	amiVideo_ULong *pixels;
+	
+	/** Indicates whether the pixel memory is allocated and needs to be freed */
+	int memoryAllocated;
+    }
+    uncorrectedRGBFormat;
+    
+    /**
+     * Contains the screen in a format that has the correct aspect ratio, as
+     * Amiga displays have only have a horizontal pixel resolution and interlace
+     * mode doubling the amount of available scanlines.
+     *
+     * A lowres pixel is composed of two highres pixels, thus the width of a
+     * lowres resolution screen must be scaled at least by a factor 2.
+     */
+    struct
+    {
+	/** Contains the width of the corrected screen */
+	int width;
+	
+	/** Contains the height of the corrected screen */
+	int height;
+	
+	/** Contains the padded width of the corrected screen (usually rounded up to the nearest 4-byte boundary) */
+	unsigned int pitch;
+	
+	/** Contains the amount of bytes per pixel (1 = chunky, 4 = RGB) */
+	unsigned int bytesPerPixel;
+	
+	/* Specifies the width of a lowres pixel in real pixels. Usually 2 is sufficient. To support super hires displays, 4 is required. */
+	unsigned int lowresPixelScaleFactor;
+	
+	/** Contains the pixel data */
+	void *pixels;
+    }
+    correctedFormat;
+};
+
+typedef enum
+{
+    AMIVIDEO_CHUNKY_FORMAT = 1,
+    AMIVIDEO_RGB_FORMAT = 4
+}
+amiVideo_ColorFormat;
+
+/**
+ * Initializes a screen instance with the given dimensions, bitplane depth,
+ * specific size of color components and viewport mode.
+ *
+ * @param screen Screen conversion structure
+ * @param width Width of the screen in pixels
+ * @param height Height of the screen in scanlines
+ * @param bitplaneDepth Bitplane depth, a value between 1-6 (OCS/ECS) and 1-8 (AGA)
+ * @param bitsPerColorChannel The amount of bits for used for a color component (4 = ECS/OCS, 8 = AGA)
+ * @param viewportMode The viewport mode value
+ */
+void amiVideo_initScreen(amiVideo_Screen *screen, amiVideo_Word width, amiVideo_Word height, unsigned int bitplaneDepth, unsigned int bitsPerColorChannel, amiVideo_Long viewportMode);
+
+/**
+ * Creates a screen conversion structure on the heap with the given dimensions,
+ * bitplane depth, specific size of color components and viewport mode. The
+ * resulting screen must eventually be freed from memory by calling amiVideo_freeScreen()
+ *
+ * @param width Width of the screen in pixels
+ * @param height Height of the screen in scanlines
+ * @param bitplaneDepth Bitplane depth, a value between 1-6 (OCS/ECS) and 1-8 (AGA)
+ * @param bitsPerColorChannel The amount of bits for used for a color component (4 = ECS/OCS, 8 = AGA)
+ * @param viewportMode The viewport mode value
+ * @return A screen conversion structure with the given properties
+ */
+amiVideo_Screen *amiVideo_createScreen(amiVideo_Word width, amiVideo_Word height, unsigned int bitplaneDepth, unsigned int bitsPerColorChannel, amiVideo_Long viewportMode);
+
+/**
+ * Frees the heap allocated members of the given screen structure.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_cleanupScreen(amiVideo_Screen *screen);
+
+/**
+ * Frees the given screen conversion structure and its members.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_freeScreen(amiVideo_Screen *screen);
+
+/**
+ * Calculates the width of a surface that has corrected the aspect ratio.
+ *
+ * @param lowresPixelScaleFactor Specifies the width of a lowres pixel in real pixels. Usually 2 is sufficient. To support super hires displays, 4 is required.
+ * @param width Width of the uncorrected surface
+ * @param viewportMode The viewport mode value
+ */
+int amiVideo_calculateCorrectedWidth(unsigned int lowresPixelScaleFactor, amiVideo_Long width, amiVideo_Long viewportMode);
+
+/**
+ * Calculates the height of a surface that has corrected the aspect ratio.
+ *
+ * @param lowresPixelScaleFactor Specifies the width of a lowres pixel in real pixels. Usually 2 is sufficient. To support super hires displays, 4 is required.
+ * @param height Height of the uncorrected surface
+ * @param viewportMode The viewport mode value
+ */
+int amiVideo_calculateCorrectedHeight(unsigned int lowresPixelScaleFactor, amiVideo_Long height, amiVideo_Long viewportMode);
+
+/**
+ * @param screen Screen conversion structure
+ * @param lowresPixelScaleFactor Specifies the width of a lowres pixel in real pixels. Usually 2 is sufficient. To support super hires displays, 4 is required.
+ */
+void amiVideo_setLowresPixelScaleFactor(amiVideo_Screen *screen, unsigned int lowresPixelScaleFactor);
+
+/**
+ * Sets the bitplane pointers of the conversion structure to the appropriate
+ * memory positions. On AmigaOS these may point to a real viewport's bitplane
+ * pointers. On different platforms these may point to subsets of a
+ * pre-allocated memory area containing planar graphics data.
+ *
+ * @param screen Screen conversion structure
+ * @param bitplanes Pointers to bitplane areas in memory
+ */
+void amiVideo_setScreenBitplanePointers(amiVideo_Screen *screen, amiVideo_UByte **bitplanes);
+
+/**
+ * Automatically sets the bitplane pointers of the conversion structure to the
+ * right subsets in a given memory area containing planar graphics data. It
+ * assumes that planar data for each bitplane level are stored immediately after
+ * each other.
+ *
+ * @param screen Screen conversion structure
+ * @param bitplanes A memory area containing planar graphics data
+ */
+void amiVideo_setScreenBitplanes(amiVideo_Screen *screen, amiVideo_UByte *bitplanes);
+
+/**
+ * Sets the uncorrected chunky sub struct pointer to a memory area capable of
+ * storing it.
+ *
+ * @param screen Screen conversion structure
+ * @param pixels Pointer to a memory struct storing chunky pixels
+ * @param pitch Padded width of the memory surface in bytes
+ */
+void amiVideo_setScreenUncorrectedChunkyPixelsPointer(amiVideo_Screen *screen, amiVideo_UByte *pixels, unsigned int pitch);
+
+/**
+ * Sets the uncorrected RGB sub struct pointer to a memory area capable of
+ * storing it.
+ *
+ * @param screen Screen conversion structure
+ * @param pixels Pointer to a memory area storing RGB pixels
+ * @param pitch Padded width of the memory surface in bytes (usually 4 * width, but it may be padded)
+ * @param allocateUncorrectedMemory Indicates whether we should allocate memory for a chunky pixels buffer that should be freed
+ * @param rshift The amount of bits that we have to left shift the red color component
+ * @param gshift The amount of bits that we have to left shift the green color component
+ * @param bshift The amount of bits that we have to left shift the blue color component
+ * @param ashift The amount of bits that we have to left shift the alpha color component
+ */
+void amiVideo_setScreenUncorrectedRGBPixelsPointer(amiVideo_Screen *screen, amiVideo_ULong *pixels, unsigned int pitch, int allocateUncorrectedMemory, amiVideo_UByte rshift, amiVideo_UByte gshift, amiVideo_UByte bshift, amiVideo_UByte ashift);
+
+/**
+ * Sets the corrected pixels sub struct pointer to a memory area capable of
+ * storing it.
+ *
+ * @param screen Screen conversion structure
+ * @param pixels Pointer to a memory area storing the corrected pixels
+ * @param pitch Padded width of the memory surface in bytes (equals witdth for chunky, 4 * width for RGB, but it may be padded)
+ * @param bytesPerPixel Specifies of how many bytes a pixel consists (1 = chunky, 4 = RGB)
+ * @param allocateUncorrectedMemory Indicates whether we should allocate memory for a chunky or RGB pixel buffer that should be freed
+ * @param rshift The amount of bits that we have to left shift the red color component
+ * @param gshift The amount of bits that we have to left shift the green color component
+ * @param bshift The amount of bits that we have to left shift the blue color component
+ * @param ashift The amount of bits that we have to left shift the alpha color component
+ */
+void amiVideo_setScreenCorrectedPixelsPointer(amiVideo_Screen *screen, void *pixels, unsigned int pitch, unsigned int bytesPerPixel, int allocateUncorrectedMemory, amiVideo_UByte rshift, amiVideo_UByte gshift, amiVideo_UByte bshift, amiVideo_UByte ashift);
+
+/**
+ * Converts the bitplanes to chunky pixels in which every byte represents a
+ * pixel and an index value from the palette.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_convertScreenBitplanesToChunkyPixels(amiVideo_Screen *screen);
+
+/**
+ * Converts the chunky pixels to RGB pixels in which every four bytes represent
+ * the color value of a pixel.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_convertScreenChunkyPixelsToRGBPixels(amiVideo_Screen *screen);
+
+/**
+ * Converts chunky pixels to bitplane format in which every bit represents a
+ * part of an index value of the palette of a pixel.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_convertScreenChunkyPixelsToBitplanes(amiVideo_Screen *screen);
+
+/**
+ * Corrects the chunky or RGB pixel surface into a surface having the correct
+ * aspect ratio taking the resolution settings into account.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_correctScreenPixels(amiVideo_Screen *screen);
+
+/**
+ * Converts the screen bitplane surface to RGB pixel surface and performs all
+ * the immediate steps.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_convertScreenBitplanesToRGBPixels(amiVideo_Screen *screen);
+
+/**
+ * Converts the screen bitplanes surface to a corrected chunky pixel surface and
+ * performs all the immediate steps.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_convertScreenBitplanesToCorrectedChunkyPixels(amiVideo_Screen *screen);
+
+/**
+ * Converts the screen bitplanes surface to a corrected RGB pixel surface and
+ * performs all the immediate steps.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_convertScreenBitplanesToCorrectedRGBPixels(amiVideo_Screen *screen);
+
+/**
+ * Converts the uncorrected chunky pixel surface to a corrected RGB pixel surface
+ * and performs all the immediate steps.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_convertScreenChunkyPixelsToCorrectedRGBPixels(amiVideo_Screen *screen);
+
+/**
+ * Auto selects the most efficient display format for displaying the converted
+ * screen. It picks RGB format for HAM displays and when 24 or 32 bitplanes are
+ * used. In all other cases, it picks chunky format.
+ *
+ * @param viewportMode Amiga viewport register value
+ * @return The most efficient color format
+ */
+amiVideo_ColorFormat amiVideo_autoSelectColorFormat(const amiVideo_Screen *screen);
+
+/**
+ * Reorders the RGB pixels from the 0RGB (for 24 bitplanes) or RGBA (for 32
+ * bitplanes) representation to the byte order that is actually used for the
+ * display screen.
+ *
+ * @param screen Screen conversion structure
+ */
+void amiVideo_reorderRGBPixels(amiVideo_Screen *screen);
+
+#endif

+ 82 - 0
ilbm.mod/libamivideo/src/libamivideo/viewportmode.c

@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "viewportmode.h"
+
+int amiVideo_checkExtraHalfbrite(const amiVideo_Long viewportMode)
+{
+    return ((viewportMode & AMIVIDEO_VIDEOPORTMODE_EHB) == AMIVIDEO_VIDEOPORTMODE_EHB);
+}
+
+int amiVideo_checkHoldAndModify(const amiVideo_Long viewportMode)
+{
+    return ((viewportMode & AMIVIDEO_VIDEOPORTMODE_HAM) == AMIVIDEO_VIDEOPORTMODE_HAM);
+}
+
+int amiVideo_checkHires(const amiVideo_Long viewportMode)
+{
+    return ((viewportMode & AMIVIDEO_VIDEOPORTMODE_HIRES) == AMIVIDEO_VIDEOPORTMODE_HIRES);
+}
+
+int amiVideo_checkSuperHires(const amiVideo_Long viewportMode)
+{
+    return ((viewportMode & AMIVIDEO_VIDEOPORTMODE_SUPERHIRES) == AMIVIDEO_VIDEOPORTMODE_SUPERHIRES);
+}
+
+int amiVideo_checkLaced(const amiVideo_Long viewportMode)
+{
+    return ((viewportMode & AMIVIDEO_VIDEOPORTMODE_LACE) == AMIVIDEO_VIDEOPORTMODE_LACE);
+}
+
+unsigned int amiVideo_autoSelectLowresPixelScaleFactor(const amiVideo_Long viewportMode)
+{
+    if(amiVideo_checkSuperHires(viewportMode))
+	return 4;
+    else if(amiVideo_checkHires(viewportMode) && amiVideo_checkLaced(viewportMode))
+	return 1;
+    else if(amiVideo_checkHires(viewportMode) && !amiVideo_checkLaced(viewportMode))
+	return 2;
+    else if(amiVideo_checkLaced(viewportMode))
+	return 2;
+    else
+	return 1;
+}
+
+amiVideo_Long amiVideo_extractPaletteFlags(const amiVideo_Long viewportMode)
+{
+    return viewportMode & (AMIVIDEO_VIDEOPORTMODE_HAM | AMIVIDEO_VIDEOPORTMODE_EHB);
+}
+
+amiVideo_Long amiVideo_autoSelectViewportMode(const amiVideo_Word width, const amiVideo_Word height)
+{
+    amiVideo_Long viewportMode = 0;
+    
+    if(width > 736)
+	viewportMode |= AMIVIDEO_VIDEOPORTMODE_SUPERHIRES; /* If the page width is larger than 736 (640 width + max overscan), we use super hi-res screen mode */
+    else if(width > 368)
+	viewportMode |= AMIVIDEO_VIDEOPORTMODE_HIRES; /* If the page width is larger than 368 (320 width + max overscan), we use hi-res screen mode */
+
+    /* If the page height is larger than 290 (256 height + max overscan), we have a laced screen mode */
+    if(height > 290)
+	viewportMode |= AMIVIDEO_VIDEOPORTMODE_LACE;
+
+    return viewportMode;
+}

+ 101 - 0
ilbm.mod/libamivideo/src/libamivideo/viewportmode.h

@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __AMIVIDEO_VIEWPORTMODE_H
+#define __AMIVIDEO_VIEWPORTMODE_H
+#include "amivideotypes.h"
+
+#define AMIVIDEO_VIDEOPORTMODE_LACE 0x0004
+#define AMIVIDEO_VIDEOPORTMODE_EHB 0x80
+#define AMIVIDEO_VIDEOPORTMODE_HAM 0x800
+#define AMIVIDEO_VIDEOPORTMODE_HIRES 0x8000
+#define AMIVIDEO_VIDEOPORTMODE_SUPERHIRES 0x8020
+
+/**
+ * Checks whether the Extra-Halfbrite (EHB) bit is enabled in the viewport mode register.
+ *
+ * @param viewportMode Amiga viewport register value
+ * @return TRUE if Extra-Halfbrite is enabled, else FALSE
+ */
+int amiVideo_checkExtraHalfbrite(const amiVideo_Long viewportMode);
+
+/**
+ * Checks whether the Hold-and-Modify (HAM) bit is enabled in the viewport mode register.
+ *
+ * @param viewportMode Amiga viewport register value
+ * @return TRUE if Extra-Halfbrite is enabled, else FALSE
+ */
+int amiVideo_checkHoldAndModify(const amiVideo_Long viewportMode);
+
+/**
+ * Checks whether the hires bit is enabled in the viewport mode register.
+ *
+ * @param viewportMode Amiga viewport register value
+ * @return TRUE if the hires bit is enabled, else FALSE
+ */
+int amiVideo_checkHires(const amiVideo_Long viewportMode);
+
+/**
+ * Checks whether the super and hires bits are enabled in the viewport mode
+ * register.
+ *
+ * @param viewportMode Amiga viewport register value
+ * @return TRUE if the hires and super bits are enabled, else FALSE
+ */
+int amiVideo_checkSuperHires(const amiVideo_Long viewportMode);
+
+/**
+ * Checks whether the hires bit is enabled in the viewport mode register.
+ *
+ * @param viewportMode Amiga viewport register value
+ * @return TRUE if the hires bit is enabled, else FALSE
+ */
+int amiVideo_checkLaced(const amiVideo_Long viewportMode);
+
+/**
+ * Auto selects the most space efficient lowres pixel scale factor capable of
+ * retaining the right aspect ratio on non-Amiga displays.
+ *
+ * @param viewportMode Amiga viewport register value
+ * @return The most efficient lowres pixel scale factor
+ */
+unsigned int amiVideo_autoSelectLowresPixelScaleFactor(const amiVideo_Long viewportMode);
+
+/**
+ * Extracts the palette flag values bits (Extra Half Brite and Hold-and Modify)
+ * from the viewport mode value.
+ *
+ * @param viewportMode Amiga viewport register value
+ * @return A viewport mode value with only the EHB and HAM flags set
+ */
+amiVideo_Long amiVideo_extractPaletteFlags(const amiVideo_Long viewportMode);
+
+/**
+ * Auto selects the most suitable Amiga resolution viewport flags to display a
+ * given screen.
+ *
+ * @param width Width of the screen
+ * @param height Height of the screen
+ * @return A viewport mode value with the most suitable resolution flags set
+ */
+amiVideo_Long amiVideo_autoSelectViewportMode(const amiVideo_Word width, const amiVideo_Word height);
+
+#endif

+ 7 - 0
ilbm.mod/libamivideo/tests/Makefile.am

@@ -0,0 +1,7 @@
+check_PROGRAMS = chunky
+
+chunky_SOURCES = chunky.c
+chunky_LDADD = ../src/libamivideo/libamivideo.la
+chunky_CFLAGS = -I../src/libamivideo
+
+TESTS = chunky

+ 61 - 0
ilbm.mod/libamivideo/tests/chunky.c

@@ -0,0 +1,61 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <screen.h>
+
+#define WIDTH 32
+#define HEIGHT 20
+#define BITPLANE_DEPTH 4
+
+amiVideo_UByte pixels[] = {
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+    0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2,
+    0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3,
+    0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
+    0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x6, 0x6, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
+    0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
+    0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xa, 0xa, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
+    0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xb, 0xb, 0xb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
+    0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xc, 0xc, 0xc, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
+    0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xd, 0xd, 0xd, 0xd, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
+    0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5,
+};
+
+int main(int argc, char *argv[])
+{
+    amiVideo_UByte *newPixels = (amiVideo_UByte*)malloc(WIDTH * HEIGHT * sizeof(amiVideo_UByte));
+    amiVideo_UByte *bitplanes = (amiVideo_UByte*)malloc(WIDTH * HEIGHT * sizeof(amiVideo_UByte));
+    amiVideo_Screen screen;
+    int status;
+    
+    memcpy(newPixels, pixels, WIDTH * HEIGHT * sizeof(amiVideo_UByte));
+    
+    amiVideo_initScreen(&screen, WIDTH, HEIGHT, BITPLANE_DEPTH, 8, 0);
+    amiVideo_setScreenUncorrectedChunkyPixelsPointer(&screen, newPixels, WIDTH);
+    amiVideo_setScreenBitplanes(&screen, bitplanes);
+    
+    amiVideo_convertScreenChunkyPixelsToBitplanes(&screen);
+    amiVideo_convertScreenBitplanesToChunkyPixels(&screen);
+    
+    if(memcmp(pixels, newPixels, WIDTH * HEIGHT) == 0)
+	status = 0;
+    else
+    {
+	fprintf(stderr, "The pixel areas are not identical!\n");
+	status = 1;
+    }
+    
+    free(bitplanes);
+    amiVideo_cleanupScreen(&screen);
+    
+    return status;
+}

+ 1 - 0
ilbm.mod/libamivideo/version

@@ -0,0 +1 @@
+0.1

+ 1 - 0
ilbm.mod/libiff/AUTHORS

@@ -0,0 +1 @@
+Sander van der Burg <[email protected]>

+ 18 - 0
ilbm.mod/libiff/COPYING

@@ -0,0 +1,18 @@
+Copyright (c) 2012 Sander van der Burg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 0 - 0
ilbm.mod/libiff/ChangeLog


+ 365 - 0
ilbm.mod/libiff/INSTALL

@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+

+ 1 - 0
ilbm.mod/libiff/Makefile.am

@@ -0,0 +1 @@
+SUBDIRS = doc src tests

+ 0 - 0
ilbm.mod/libiff/NEWS


+ 1 - 0
ilbm.mod/libiff/README

@@ -0,0 +1 @@
+README.md

+ 606 - 0
ilbm.mod/libiff/README.md

@@ -0,0 +1,606 @@
+libiff
+======
+`libiff` is a portable, extensible parser library implemented in ANSI C, for
+EA-IFF 85: Electronic Arts' Interchange File Format (IFF). It offers the
+following features:
+
+* Reading IFF files
+* Programmatically creating IFF files
+* Retrieving IFF file contents
+* Writing IFF files
+* IFF conformance checking
+
+Furthermore, this library has an extensible parser interface, which makes it
+possible to parse chunk types defined in application formats.
+
+What is the Interchange File Format (IFF)?
+==========================================
+IFF is a generic container format designed to make the transfer of data
+easier between applications produced by different vendors. The main purpose is to
+divide files into chunks identified by a type ID consisting of 4 characters,
+followed by a chunk size and the specified number of bytes. The IFF standard
+also defines a number of predefined _group_ chunks, which can be used to group
+data chunks together and to share a set of common properties over a number of
+sub chunks.
+
+The IFF container format is frequently used by applications on the Commodore
+Amiga for storing images, music and audio samples. The actual IFF specification
+can be found in: `doc/IFF.asc`, which is included in this package.
+
+Some _application_ file formats using the IFF container are:
+
+* ILBM, used for storing images. Quite often ILBM files are _wrongly_ named as IFF files because ILBM is the most common application format
+* ANIM, an extension to ILBM supporting animations which are delta compressed
+* 8SVX, used for storing 8-bit sound samples
+* SMUS, used for storing musical scores
+
+This library does not implement support for these subformats, but instead the
+parser provides an extension interface, which can be used to handle chunks
+defined in these application formats. For example, the `libilbm` package,
+provides additional functions to parse ILBM image chunks by extending this IFF
+parser. You can easily extend the IFF parser yourself to define your own custom
+file format on top of IFF.
+
+Installation on Unix-like systems
+=================================
+Compilation and installation of this library on Unix-like systems is straight
+forward, by using the standard GNU autotools build instructions:
+
+    $ ./configure
+    $ make
+    $ make install
+
+More details about the installation process can be found in the `INSTALL` file
+included in this package.
+
+Building with Visual C++
+========================
+This package can also be built with Visual C++ for Windows platforms. First, you
+must copy `src/libiff/ifftypes.h.in` to `src/libiff/ifftypes.h` and edit the the
+latter file.
+
+Change the line:
+
+```C
+#define IFF_BIG_ENDIAN @IFF_BIG_ENDIAN@
+```
+
+into
+
+```C
+#define IFF_BIG_ENDIAN 0
+```
+
+Then you can open the solution file: `src/libiff.sln` in Visual Studio to edit or
+build it. Alternatively, you can use `MSBuild` to compile it:
+
+    $ MSBuild libiff.sln
+
+The output is produced in the `Debug/` directory.
+
+Portability
+===========
+Because this package is implemented in ANSI C (with the small exception that the
+command line utilities use `getopt()` ), it should be pretty easy to port this
+package to new platforms. So far it's tested on the following platforms:
+
+* Linux (`i686-linux`, `x86_64-linux`) using GCC
+* Cygwin (`i686-cygwin`, `x86_64-cygwin`) using GCC
+* AmigaOS (`m68k-amigaos`) using EGCS through Geek Gadgets
+* Windows (`i686-windows`) using Visual C++ 2013
+
+License
+=======
+This library is available under the MIT license
+
+Using the IFF library API
+=========================
+Using the IFF API to create, read, write and check IFF files is pretty
+straight forward. Full API documentation can be found in the `doc/apidox`
+directory of this package.
+
+Reading IFF files
+-----------------
+To read IFF files, include the `iff.h` header file and call the `IFF_read()`
+function:
+
+```C
+#include <libiff/iff.h>
+
+int main(int argc, char *argv[])
+{
+    /* Read an IFF file */
+    IFF_Chunk *chunk = IFF_read("input.IFF", NULL, 0);
+    
+    if(chunk == NULL)
+    {
+        /* Use the chunk instance for some purpose here */
+        
+        return 0;
+    }
+    else
+        return 1; /* The chunk cannot be read for some reason */
+}
+```
+
+Programatically creating IFF files
+----------------------------------
+An IFF file can be created by composing various IFF struct instances together.
+The following example creates a concatenation chunk containing a 'TEST' form.
+The 'TEST' form contains a 'HELO' chunk containing "abcd", and a 'BYE ' chunk
+containing "1234":
+
+```C
+#include <stdlib.h>
+#include <libiff/iff.h>
+#include <libiff/rawchunk.h>
+#include <libiff/form.h>
+#include <libiff/cat.h>
+
+#define HELO_BYTES_SIZE 4
+#define BYE_BYTES_SIZE 4
+
+int main(int argc, char *argv[])
+{
+    /* Declarations */
+    IFF_UByte *heloChunkData, *byteChunkData;
+    IFF_RawChunk *heloChunk, *byeChunk;
+    IFF_Form *form;
+    IFF_CAT *cat;
+    
+    /* Allocate and create data for the 'HELO' chunk */
+    heloChunkData = (IFF_UByte*)malloc(HELO_BYTES_SIZE * sizeof(IFF_UByte));
+    heloChunkData[0] = 'a';
+    heloChunkData[1] = 'b';
+    heloChunkData[2] = 'c';
+    heloChunkData[3] = 'd';
+    
+    /* Create the actual 'HELO' chunk */
+    heloChunk = IFF_createRawChunk("HELO");
+    
+    /* Attach the chunk data to the 'HELO' chunk */
+    IFF_setRawChunkData(heloChunk, heloChunkData, HELO_BYTES_SIZE);
+    
+    /* Allocate and create data for the 'BYE ' chunk */
+    byeChunkData = (IFF_UByte*)malloc(BYE_BYTES_SIZE * sizeof(IFF_UByte));
+    byeChunkData[0] = '1';
+    byeChunkData[1] = '2';
+    byeChunkData[2] = '3';
+    byeChunkData[3] = '4';
+    
+    /* Create the actual 'BYE ' chunk and attach the data to it */
+    byeChunk = IFF_createRawChunk("BYE ");
+    IFF_setRawChunkData(byeChunk, byeChunkData, BYE_BYTES_SIZE);
+    
+    /* Create the 'TEST' form chunk */
+    form = IFF_createForm("TEST");
+    
+    /* Attach the 'HELO' and 'BYE ' chunk to the form */
+    IFF_addToForm((IFF_Chunk*)heloChunk);
+    IFF_addToForm((IFF_Chunk*)byeChunk);
+    
+    /* Create a concatenation chunk */
+    cat = IFF_createCAT("TEST");
+    
+    /* Attach the form to the concatenation chunk */
+    IFF_addToCAT((IFF_Chunk*)form);
+    
+    return 0;
+}
+```
+
+Retrieving IFF file contents
+----------------------------
+Quite often you need to retrieve specific properties from an IFF file that are
+interesting to you, while you may want to ignore the pieces that are not
+relevant.
+
+The scope of most application formats are restricted to a FORM with a particular
+form type. For example, ILBM files (which purpose is to store graphics) are
+essentially FORM chunks with an ILBM form type. Inside these forms various
+aspects of the picture are specified, such as the resolution, color values of
+the palette and planar graphics data. The `IFF_searchForms()` function
+recursively searches for all form chunks with the given form type inside an IFF
+file.
+
+Furthermore, each form chunk contains an arbitrary number of
+data chunks or other group chunks. The `IFF_getChunkFromForm()` function can be
+used to retrieve a property from a form. Furthermore, if the given form is a
+member of a list chunk, which uses shared properties, it also recursively looks 
+up the shared property value, if the requested property has not been defined in 
+the form itself.
+
+It may also be possible that there are more occurences of the same chunk inside 
+a form. In these cases, the `IFF_getChunksFromForm()` can be used to retrieve
+all possible values, however this function does not take the shared properties
+of a list into account.
+
+The following example shows how these functions can be used:
+
+```C
+#include <libiff/chunk.h>
+#include <libiff/form.h>
+
+int main(int argc, char *argv[])
+{
+    /* Declarations */
+    IFF_Chunk *chunk;
+    IFF_Form **ilbmForms;
+    unsigned int ilbmFormsLength, i;
+    
+    /* Create or read an IFF file here */
+    
+    /* Search for all forms having an ILBM form type */
+    ilbmForms = IFF_searchForms(chunk, "ILBM", &ilbmFormsLength);
+    
+    /* Iterate over all ILBM forms in the given IFF file */
+    
+    for(i = 0; i < ilbmFormsLength; i++)
+    {
+        IFF_Form *ilbmForm = ilbmForms[i];
+        unsigned int colorRangesLength;
+        
+        /* Retrieve the BMHD data property from the ILBM form */
+        IFF_Chunk *bitMapHeader = IFF_getChunkFromForm(ilbmForm, "BMHD");
+        
+        /* Retrieve all possible CRNG properties from the ILBM form */
+        IFF_Chunk **colorRanges = IFF_getChunksFromForm(ilbmForm, "CRNG", &colorRangesLength);
+    }
+    
+    return 0;
+}
+```
+
+Writing IFF files
+-----------------
+A composition of chunks can be written as an IFF file by invoking the
+`IFF_write()` function:
+
+```C
+#include <libiff/iff.h>
+
+int main(int argc, char *argv[])
+{
+    IFF_Chunk *chunk;
+    
+    /* Create or read a chunk */
+    
+    if(IFF_write("output.IFF", chunk, NULL, 0))
+        return 0; /* The file has been successfully written */
+    else
+        return 1; /* Some error occured */
+}
+```
+
+IFF conformance checking
+------------------------
+The IFF standard defines several constraints that may not be violated. For
+example, chunk IDs may only contain ASCII characters from a certain range in the
+ASCII table. Furthermore, the chunk size of a group chunk must be correct and
+may not be truncated. The `IFF_check()` function can be used to check whether a
+composition of chunks conform to the IFF standard:
+
+```C
+#include <libiff/iff.h>
+
+int main(int argc, char *argv[])
+{
+    IFF_Chunk *chunk;
+    
+    /* Create or read a chunk here */
+    
+    if(IFF_check(chunk, NULL, 0))
+        return 0; /* A valid IFF file */
+    else
+        return 1; /* Not a valid IFF file */
+}
+```
+
+Comparing IFF chunk hierarchies
+-------------------------------
+In some cases, it may also be useful to compare IFF chunk hierarchies. For
+example, to check whether to files (or subsets thereof) are identical. These
+hierarchies can be compared by using the `IFF_compare()` function:
+
+```C
+#include <libiff/iff.h>
+
+int main(int argc, char *argv[])
+{
+    IFF_Chunk *chunk1, *chunk2;
+    
+    /* Read or create the chunks here */
+
+    if(IFF_compare(chunk1, chunk2, NULL, 0))
+        return 0; /* Both chunk hierarchies are equal */
+    else
+        return 1; /* Both chunk hierarchies are not equal */
+}
+```
+
+Command-line utilities
+======================
+Apart from an API to handle IFF files, this package also includes a number of
+command-line utilities to make usage of IFF files more convenient:
+
+* `iffpp` can be used to pretty print an IFF file into a textual representation, so that it can be manually inspected
+* `iffjoin` can be used to join an arbitrary number of IFF files into a new IFF file storing these in an concationation chunk
+
+Consult the manual pages of these tools for more information.
+
+Extending the IFF parser
+========================
+This package only implements a generic IFF parser, which provides support for a
+number of group chunks and "raw" data chunks. Application formats typically
+define various other data chunks, each having their own structure. In order to
+support a particular application format, the IFF parser needs to be extended.
+
+To implement a parser for an application format you need to:
+
+* Create an application format interface
+* Implement extension chunk modules
+
+Creating an application format interface
+----------------------------------------
+Every function in the `iff.h` header require at least two parameters, which are
+named `extension` and `extensionLength`. So far, we have omitted these extension
+parameters by specifying a NULL pointer and a 0 length.
+
+These function parameters can be used to support application format chunks by
+specifying an array of form types pointing to a functions which read, write,
+free, check and print extension chunks for a given data property.
+
+Because it is incovenient to bother library users with specifying these
+paramaters over and over again, it is recommended to create a new application
+format interface, which hides these details. For example, in the `libilbm`
+package, you can include the `ilbm.h` header file, instead of the `iff.h` header
+file to conveniently access ILBM files and their application chunks.
+
+The following example shows how to define a header file (`test.h`) for the
+interface of an imaginary TEST file format:
+
+```C
+#ifndef __TEST_H
+#define __TEST_H
+
+#include <stdio.h>
+#include <libiff/chunk.h>
+
+IFF_Chunk *TEST_read(const char *filename);
+
+int TEST_write(const char *filename, const IFF_Chunk *chunk);
+
+void TEST_free(IFF_Chunk *chunk);
+
+void TEST_print(const IFF_Chunk *chunk, const unsigned int indentLevel);
+
+int TEST_compare(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2);
+
+#endif
+```
+
+As you may notice, this header file is almost the same as the `iff.h` header
+file, except that the `IFF_` prefixes are replaced by the `TEST_` prefixes and
+the `extension` and `extensionLength` parameters are removed.
+
+The implementation of this interface (`test.c`) may look as follows:
+
+```C
+#include "test.h"
+#include <libiff/iff.h>
+#include "hello.h"
+#include "bye.h"
+
+#define TEST_NUM_OF_FORM_TYPES 1
+#define TEST_NUM_OF_EXTENSION_CHUNKS 2
+
+/*
+ * Defines the 'HELO' and 'BYE ' extension chunks and referes to the
+ * functions that handles them. The chunks must be alphabetically sorted so
+ * that they can be found by a binary search algorithm.
+ */
+static IFF_FormExtension testFormExtension[] = {
+    {"BYE ", &TEST_readBye, &TEST_writeBye, &TEST_checkBye, &TEST_freeBye, &TEST_printBye, &TEST_compareBye},
+    {"HELO", &TEST_readHello, &TEST_writeHello, &TEST_checkHello, &TEST_freeHello, &TEST_printHello, &TEST_compareHello}
+};
+
+/*
+ * Refers to the extension chunk defintions within the TEST form scope.
+ * Also these form types must be alphabetically sorted.
+ */
+static IFF_Extension extension[] = {
+    {"TEST", TEST_NUM_OF_EXTENSION_CHUNKS, testFormExtension}
+};
+
+/* The following functions hide the the extension parameters for this application format */
+IFF_Chunk *TEST_read(const char *filename)
+{
+    return IFF_read(filename, extension, TEST_NUM_OF_FORM_TYPES);
+}
+
+int TEST_write(const char *filename, const IFF_Chunk *chunk)
+{
+    return IFF_write(filename, chunk, extension, TEST_NUM_OF_FORM_TYPES);
+}
+
+void TEST_free(IFF_Chunk *chunk)
+{
+    IFF_free(chunk, NULL, extension, TEST_NUM_OF_FORM_TYPES);
+}
+
+void TEST_print(const IFF_Chunk *chunk, const unsigned int indentLevel)
+{
+    IFF_print(chunk, indentLevel, extension, TEST_NUM_OF_FORM_TYPES);
+}
+
+int TEST_compare(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2)
+{
+    return IFF_compare(chunk1, chunk2, extension, TEST_NUM_OF_FORM_TYPES);
+}
+```
+
+In the code fragment above, an array defining extension chunkIDs and function
+pointers (`testFormExtension`) specifies how to read, write, check, free and
+print each individual application chunk. The other array binds these extension
+chunks into the scope of the TEST form type. This ensures that the TEST.HELO
+property is parsed by our extension function and that a chunk with the same ID
+in a different form type is parsed ABCD.HELO differently (because they are not
+the same).
+
+In the remainder of the interface, we simply call all the functions defined in
+`iff.h` with the given `extension` and `extensionLength` parameters dealing with
+application format chunks of the TEST format.
+
+Implementing extension chunk modules
+------------------------------------
+Now that we have defined an application interface, you also need to specify how
+to read, write, free, check and print these application chunks. For each
+application chunk, you define a seperate module with an header the may look like
+this (this example defines `hello.h` to which the previous example refers):
+
+```C
+#ifndef __TEST_HELLO_H
+#define __TEST_HELLO_H
+
+#include <stdio.h>
+#include <libiff/ifftypes.h>
+#include <libiff/group.h>
+#include <libiff/chunk.h>
+
+typedef struct
+{
+    /* These struct members are mandatory for every chunk */
+    IFF_Group *parent;
+
+    IFF_ID chunkId;
+    IFF_Long chunkSize;
+
+    /* The remainder of the struct contains custom properties */
+    IFF_UByte a;
+    IFF_UByte b;
+    IFF_UWord c;
+}
+TEST_Hello;
+
+TEST_Hello *TEST_createHello(void);
+
+IFF_Chunk *TEST_readHello(FILE *file, const IFF_Long chunkSize);
+
+int TEST_writeHello(FILE *file, const IFF_Chunk *chunk);
+
+int TEST_checkHello(const IFF_Chunk *chunk);
+
+void TEST_freeHello(IFF_Chunk *chunk);
+
+void TEST_printHello(const IFF_Chunk *chunk, const unsigned int indentLevel);
+
+int TEST_compareHello(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2);
+
+#endif
+```
+
+The code fragment above defines the read, write, check, free, and print
+functions for the 'HELO' chunk. As you may notice, every function has the
+`TEST_` prefix, because it is part of the TEST application format. Furthermore,
+in each module every read, write, check, free and print function must have the
+same return type and function parameters.
+
+And the implementation may look as follows:
+
+```C
+#include "hello.h"
+#include <libiff/io.h>
+#include <libiff/util.h>
+#include "test.h"
+
+#define CHUNKID "HELO"
+
+TEST_Hello *TEST_createHello(void)
+{
+    TEST_Hello *hello = (TEST_Hello*)IFF_allocateChunk(CHUNKID, sizeof(TEST_Hello));
+
+    if(hello != NULL)
+        hello->chunkSize = 2 * sizeof(IFF_UByte) + sizeof(IFF_UWord);
+
+    return hello;
+}
+
+IFF_Chunk *TEST_readHello(FILE *file, const IFF_Long chunkSize)
+{
+    TEST_Hello *hello = TEST_createHello();
+
+    if(hello != NULL)
+    {
+        if(!IFF_readUByte(file, &hello->a, CHUNKID, "a"))
+        {
+            TEST_free((IFF_Chunk*)hello);
+            return NULL;
+        }
+
+        if(!IFF_readUByte(file, &hello->b, CHUNKID, "b"))
+        {
+            TEST_free((IFF_Chunk*)hello);
+            return NULL;
+        }
+
+        if(!IFF_readUWord(file, &hello->c, CHUNKID, "c"))
+        {
+            TEST_free((IFF_Chunk*)hello);
+            return NULL;
+        }
+    }
+
+    return (IFF_Chunk*)hello;
+}
+
+int TEST_writeHello(FILE *file, const IFF_Chunk *chunk)
+{
+    const TEST_Hello *hello = (TEST_Hello*)chunk;
+
+    if(!IFF_writeUByte(file, hello->a, CHUNKID, "a"))
+        return FALSE;
+
+    if(!IFF_writeUByte(file, hello->b, CHUNKID, "b"))
+        return FALSE;
+
+    if(!IFF_writeUWord(file, hello->c, CHUNKID, "c"))
+        return FALSE;
+
+    return TRUE;
+}
+
+int TEST_checkHello(const IFF_Chunk *chunk)
+{
+    return TRUE;
+}
+
+void TEST_freeHello(IFF_Chunk *chunk)
+{
+}
+
+void TEST_printHello(const IFF_Chunk *chunk, const unsigned int indentLevel)
+{
+    const TEST_Hello *hello = (const TEST_Hello*)chunk;
+
+    IFF_printIndent(stdout, indentLevel, "a = %c;\n", hello->a);
+    IFF_printIndent(stdout, indentLevel, "b = %c;\n", hello->b);
+    IFF_printIndent(stdout, indentLevel, "c = %u;\n", hello->c);
+}
+
+int TEST_compareHello(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2)
+{
+    const TEST_Hello *hello1 = (const TEST_Hello*)chunk1;
+    const TEST_Hello *hello2 = (const TEST_Hello*)chunk2;
+
+    if(hello1->a != hello2->a)
+        return FALSE;
+
+    if(hello1->b != hello2->b)
+        return FALSE;
+
+    if(hello1->c != hello2->c)
+        return FALSE;
+
+    return TRUE;
+}
+```

+ 7 - 0
ilbm.mod/libiff/bootstrap

@@ -0,0 +1,7 @@
+#!/bin/sh
+
+rm -f config.cache config.log acconfig.h aclocal.m4 README
+
+ln -s README.md README
+mkdir -p config
+autoreconf -fvi

+ 34 - 0
ilbm.mod/libiff/configure.ac

@@ -0,0 +1,34 @@
+AC_PREREQ(2.61)
+AC_INIT([libiff], m4_esyscmd_s([echo -n $(cat ./version)$VERSION_SUFFIX]))
+AC_CONFIG_AUX_DIR([config])
+AM_INIT_AUTOMAKE([1.7.2 -Wall -Werror -Wno-extra-portability])
+
+# Checks for programs
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+AM_PROG_CC_C_O
+AC_PATH_PROG(HELP2MAN, help2man, false)
+
+# Checks for headers
+AC_CHECK_HEADER([getopt.h], [HAVE_GETOPT_H=1], [HAVE_GETOPT_H=0])
+AC_SUBST(HAVE_GETOPT_H)
+
+# Endianness check
+AC_C_BIGENDIAN([IFF_BIG_ENDIAN=1],[IFF_BIG_ENDIAN=0])
+AC_SUBST(IFF_BIG_ENDIAN)
+
+# Output
+
+AC_CONFIG_FILES([
+Makefile
+doc/Makefile
+src/Makefile
+src/libiff.pc
+src/libiff/ifftypes.h
+src/libiff/Makefile
+src/iffjoin/Makefile
+src/iffpp/Makefile
+tests/Makefile
+])
+AC_OUTPUT

+ 1424 - 0
ilbm.mod/libiff/doc/IFF.asc

@@ -0,0 +1,1424 @@
+
+
+"EA IFF 85" Standard for Interchange Format Files
+
+Document Date:		January 14, 1985
+From:			Jerry Morrison, Electronic Arts
+Status of Standard:	Released and in use
+
+1. Introduction
+
+Standards are Good for Software Developers
+
+As home computer hardware evolves to better and better media machines, 
+the demand increases for higher quality, more detailed data. Data 
+development gets more expensive, requires more expertise and better 
+tools, and has to be shared across projects. Think about several ports 
+of a product on one CD-ROM with 500M Bytes of common data!
+
+Development tools need standard interchange file formats. Imagine 
+scanning in images of "player" shapes, moving them to a paint program 
+for editing, then incorporating them into a game. Or writing a theme 
+song with a Macintosh score editor and incorporating it into an Amiga 
+game. The data must at times be transformed, clipped, filled out, 
+and moved across machine kinds. Media projects will depend on data 
+transfer from graphic, music, sound effect, animation, and script 
+tools.
+
+Standards are Good for Software Users
+
+Customers should be able to move their own data between independently 
+developed software products. And they should be able to buy data libraries 
+usable across many such products. The types of data objects to exchange 
+are open-ended and include plain and formatted text, raster and structured 
+graphics, fonts, music, sound effects, musical instrument descriptions, 
+and animation.
+
+The problem with expedient file formats typically memory dumps is 
+that they're too provincial. By designing data for one particular 
+use (e.g. a screen snapshot), they preclude future expansion (would 
+you like a full page picture? a multi-page document?). In neglecting 
+the possibility that other programs might read their data, they fail 
+to save contextual information (how many bit planes? what resolution?). 
+Ignoring that other programs might create such files, they're intolerant 
+of extra data (texture palette for a picture editor), missing data 
+(no color map), or minor variations (smaller image). In practice, 
+a filed representation should rarely mirror an in-memory representation. 
+The former should be designed for longevity; the latter to optimize 
+the manipulations of a particular program. The same filed data will 
+be read into different memory formats by different programs.
+
+The IFF philosophy: "A little behind-the-scenes conversion when programs 
+read and write files is far better than NxM explicit conversion utilities 
+for highly specialized formats."
+
+So we need some standardization for data interchange among development 
+tools and products. The more developers that adopt a standard, the 
+better for all of us and our customers.
+
+Here is "EA IFF 1985"
+
+Here is our offering: Electronic Arts' IFF standard for Interchange 
+File Format. The full name is "EA IFF 1985". Alternatives and justifications 
+are included for certain choices. Public domain subroutine packages 
+and utility programs are available to make it easy to write and use 
+IFF-compatible programs.
+
+Part 1 introduces the standard. Part 2 presents its requirements and 
+background. Parts 3, 4, and 5 define the primitive data types, FORMs, 
+and LISTs, respectively, and how to define new high level types. Part 
+6 specifies the top level file structure. Appendix A is included for 
+quick reference and Appendix B names the committee responsible for 
+this standard.
+
+References
+
+American National Standard Additional Control Codes for Use with ASCII, 
+ANSI standard 3.64-1979 for an 8-bit character set. See also ISO standard 
+2022 and ISO/DIS standard 6429.2.
+
+Amiga[tm] is a trademark of Commodore-Amiga, Inc.
+
+C, A Reference Manual, Samuel P. Harbison and Guy L. Steele Jr., Tartan 
+Laboratories. Prentice-Hall, Englewood Cliffs, NJ, 1984.
+
+Compiler Construction, An Advanced Course, edited by F. L. Bauer and 
+J. Eickel (Springer-Verlag, 1976). This book is one of many sources 
+for information on recursive descent parsing.
+
+DIF Technical Specification (c)1981 by Software Arts, Inc. DIF[tm] is 
+the format for spreadsheet data interchange developed by Software 
+Arts, Inc.
+DIF[tm] is a trademark of Software Arts, Inc.
+
+Electronic Arts[tm] is a trademark of Electronic Arts.
+
+"FTXT" IFF Formatted Text, from Electronic Arts. IFF supplement document 
+for a text format.
+
+Inside Macintosh (c) 1982, 1983, 1984, 1985 Apple Computer, Inc., a 
+programmer's reference manual.
+Apple(R) is a trademark of Apple Computer, Inc.
+Macintosh[tm] is a trademark licensed to Apple Computer, Inc.
+
+"ILBM" IFF Interleaved Bitmap, from Electronic Arts. IFF supplement 
+document for a raster image format.
+
+M68000 16/32-Bit Microprocessor Programmer's Reference Manual(c) 1984, 
+1982, 1980, 1979 by Motorola, Inc.
+
+PostScript Language Manual (c) 1984 Adobe Systems Incorporated.
+PostScript[tm] is a trademark of Adobe Systems, Inc.
+Times and Helvetica(R) are trademarks of Allied Corporation.
+
+InterScript: A Proposal for a Standard for the Interchange of Editable 
+Documents (c)1984 Xerox Corporation.
+Introduction to InterScript (c) 1985 Xerox Corporation.
+
+
+
+2. Background for Designers
+
+Part 2 is about the background, requirements, and goals for the standard. 
+It's geared for people who want to design new types of IFF objects. 
+People just interested in using the standard may wish to skip this 
+part.
+
+What Do We Need?
+
+A standard should be long on prescription and short on overhead. It 
+should give lots of rules for designing programs and data files for 
+synergy. But neither the programs nor the files should cost too much 
+more than the expedient variety. While we're looking to a future with 
+CD-ROMs and perpendicular recording, the standard must work well on 
+floppy disks.
+
+For program portability, simplicity, and efficiency, formats should 
+be designed with more than one implementation style in mind. (In practice, 
+pure stream I/O is adequate although random access makes it easier 
+to write files.) It ought to be possible to read one of many objects 
+in a file without scanning all the preceding data. Some programs need 
+to read and play out their data in real time, so we need good compromises 
+between generality and efficiency.
+
+As much as we need standards, they can't hold up product schedules. 
+So we also need a kind of decentralized extensibility where any software 
+developer can define and refine new object types without some "standards 
+authority" in the loop. Developers must be able to extend existing 
+formats in a forward- and backward-compatible way. A central repository 
+for design information and example programs can help us take full 
+advantage of the standard.
+
+For convenience, data formats should heed the restrictions of various 
+processors and environments. E.g. word-alignment greatly helps 68000 
+access at insignificant cost to 8088 programs.
+
+Other goals include the ability to share common elements over a list 
+of objects and the ability to construct composite objects containing 
+other data objects with structural information like directories.
+
+And finally, "Simple things should be simple and complex things should 
+be possible."	Alan Kay.
+
+Think Ahead
+
+Let's think ahead and build programs that read and write files for 
+each other and for programs yet to be designed. Build data formats 
+to last for future computers so long as the overhead is acceptable. 
+This extends the usefulness and life of today's programs and data.
+
+To maximize interconnectivity, the standard file structure and the 
+specific object formats must all be general and extensible. Think 
+ahead when designing an object. It should serve many purposes and 
+allow many programs to store and read back all the information they 
+need; even squeeze in custom data. Then a programmer can store the 
+available data and is encouraged to include fixed contextual details. 
+Recipient programs can read the needed parts, skip unrecognized stuff, 
+default missing data, and use the stored context to help transform 
+the data as needed.
+
+Scope
+
+IFF addresses these needs by defining a standard file structure, some 
+initial data object types, ways to define new types, and rules for 
+accessing these files. We can accomplish a great deal by writing programs 
+according to this standard, but don't expect direct compatibility 
+with existing software. We'll need conversion programs to bridge the 
+gap from the old world.
+
+IFF is geared for computers that readily process information in 8-bit 
+bytes. It assumes a "physical layer" of data storage and transmission 
+that reliably maintains "files" as strings of 8-bit bytes. The standard 
+treats a "file" as a container of data bytes and is independent of 
+how to find a file and whether it has a byte count.
+
+This standard does not by itself implement a clipboard for cutting 
+and pasting data between programs. A clipboard needs software to mediate 
+access, to maintain a "contents version number" so programs can detect 
+updates, and to manage the data in "virtual memory".
+
+Data Abstraction
+
+The basic problem is how to represent information  in a way that's 
+program-independent, compiler- independent, machine-independent, and 
+device-independent.
+
+The computer science approach is "data abstraction", also known as 
+"objects", "actors", and "abstract data types". A data abstraction 
+has a "concrete representation" (its storage format), an "abstract 
+representation" (its capabilities and uses), and access procedures 
+that isolate all the calling software from the concrete representation. 
+Only the access procedures touch the data storage. Hiding mutable 
+details behind an interface is called "information hiding". What data 
+abstraction does is abstract from details of implementing the object, 
+namely the selected storage representation and algorithms for manipulating 
+it.
+
+The power of this approach is modularity. By adjusting the access 
+procedures we can extend and restructure the data without impacting 
+the interface or its callers. Conversely, we can extend and restructure 
+the interface and callers without making existing data obsolete. It's 
+great for interchange!
+
+But we seem to need the opposite: fixed file formats for all programs 
+to access. Actually, we could file data abstractions ("filed objects") 
+by storing the data and access procedures together. We'd have to encode 
+the access procedures in a standard machine-independent programming 
+language   la PostScript. Even still, the interface can't evolve freely 
+since we can't update all copies of the access procedures. So we'll 
+have to design our abstract representations for limited evolution 
+and occasional revolution (conversion).
+
+In any case, today's microcomputers can't practically store data abstractions. 
+They can do the next best thing: store arbitrary types of data in 
+"data chunks", each with a type identifier and a length count. The 
+type identifier is a reference by name to the access procedures (any 
+local implementation). The length count enables storage-level object 
+operations like "copy" and "skip to next" independent of object type.
+
+Chunk writing is straightforward. Chunk reading requires a trivial 
+parser to scan each chunk and dispatch to the proper access/conversion 
+procedure. Reading chunks nested inside other chunks requires recursion, 
+but no lookahead or backup.
+
+That's the main idea of IFF. There are, of course, a few other detailsI
+
+Previous Work
+
+Where our needs are similar, we borrow from existing standards.
+
+Our basic need to move data between independently developed programs 
+is similar to that addressed by the Apple Macintosh desk scrap or 
+"clipboard" [Inside Macintosh chapter "Scrap Manager"]. The Scrap 
+Manager works closely with the Resource Manager, a handy filer and 
+swapper for data objects (text strings, dialog window templates, pictures, 
+fontsI) including types yet to be designed [Inside Macintosh chapter 
+"Resource Manager"]. The Resource Manager is a kin to Smalltalk's 
+object swapper.
+
+We will probably write a Macintosh desk accessory that converts IFF 
+files to and from the Macintosh clipboard for quick and easy interchange 
+with programs like MacPaint and Resource Mover.
+
+Macintosh uses a simple and elegant scheme of 4-character "identifiers" 
+to identify resource types, clipboard format types, file types, and 
+file creator programs. Alternatives are unique ID numbers assigned 
+by a central authority or by hierarchical authorities, unique ID numbers 
+generated by algorithm, other fixed length character strings, and 
+variable length strings. Character string identifiers double as readable 
+signposts in data files and programs. The choice of 4 characters is 
+a good tradeoff between storage space, fetch/compare/store time, and 
+name space size. We'll honor Apple's designers by adopting this scheme.
+
+"PICT" is a good example of a standard structured graphics format 
+(including raster images) and its many uses [Inside Macintosh chapter 
+"QuickDraw"]. Macintosh provides QuickDraw routines in ROM to create, 
+manipulate, and display PICTs. Any application can create a PICT by 
+simply asking QuickDraw to record a sequence of drawing commands. 
+Since it's just as easy to ask QuickDraw to render a PICT to a screen 
+or a printer, it's very effective to pass them between programs, say 
+from an illustrator to a word processor. An important feature is the 
+ability to store "comments" in a PICT which QuickDraw will ignore. 
+Actually, it passes them to your optional custom "comment handler".
+
+PostScript, Adobe's print file standard, is a more general way to 
+represent any print image (which is a specification for putting marks 
+on paper) [PostScript Language Manual]. In fact, PostScript is a full-fledged 
+programming language. To interpret a PostScript program is to render 
+a document on a raster output device. The language is defined in layers: 
+a lexical layer of identifiers, constants, and operators; a layer 
+of reverse polish semantics including scope rules and a way to define 
+new subroutines; and a printing-specific layer of built-in identifiers 
+and operators for rendering graphic images. It is clearly a powerful 
+(Turing equivalent) image definition language. PICT and a subset of 
+PostScript are candidates for structured graphics standards.
+
+A PostScript document can be printed on any raster output device (including 
+a display) but cannot generally be edited. That's because the original 
+flexibility and constraints have been discarded. Besides, a PostScript 
+program may use arbitrary computation to supply parameters like placement 
+and size to each operator. A QuickDraw PICT, in comparison, is a more 
+restricted format of graphic primitives parameterized by constants. 
+So a PICT can be edited at the level of the primitives, e.g. move 
+or thicken a line. It cannot be edited at the higher level of, say, 
+the bar chart data which generated the picture.
+
+PostScript has another limitation: Not all kinds of data amount to 
+marks on paper. A musical instrument description is one example. PostScript 
+is just not geared for such uses.
+
+"DIF" is another example of data being stored in a general format 
+usable by future programs [DIF Technical Specification]. DIF is a 
+format for spreadsheet data interchange. DIF and PostScript are both 
+expressed in plain ASCII text files. This is very handy for printing, 
+debugging, experimenting, and transmitting across modems. It can have 
+substantial cost in compaction and read/write work, depending on use. 
+We won't store IFF files this way but we could define an ASCII alternate 
+representation with a converter program.
+
+InterScript is Xerox' standard for interchange of editable documents 
+[Introduction to InterScript]. It approaches a harder problem: How 
+to represent editable word processor documents that may contain formatted 
+text, pictures, cross-references like figure numbers, and even highly 
+specialized objects like mathematical equations? InterScript aims 
+to define one standard representation for each kind of information. 
+Each InterScript-compatible editor is supposed to preserve the objects 
+it doesn't understand and even maintain nested cross-references. So 
+a simple word processor would let you edit the text of a fancy document 
+without discarding the equations or disrupting the equation numbers.
+
+Our task is similarly to store high level information and preserve 
+as much content as practical while moving it between programs. But 
+we need to span a larger universe of data types and cannot expect 
+to centrally define them all. Fortunately, we don't need to make programs 
+preserve information that they don't understand. And for better or 
+worse, we don't have to tackle general-purpose cross-references yet.
+
+
+
+3. Primitive Data Types
+
+Atomic components such as integers and characters that are interpretable 
+directly by the CPU are specified in one format for all processors. 
+We chose a format that's most convenient for the Motorola MC68000 
+processor [M68000 16/32-Bit Microprocessor Programmer's Reference 
+Manual].
+
+N.B.: Part 3 dictates the format for "primitive" data types where and 
+only where used in the overall file structure and standard kinds of 
+chunks (Cf. Chunks). The number of such occurrences will be small 
+enough that the costs of conversion, storage, and management of processor-
+specific files would far exceed the costs of conversion during I/O by "foreign" 
+programs. A particular data chunk may be specified with a different 
+format for its internal primitive types or with processor- or environment-
+speci fic variants if necessary to optimize local usage. Since that hurts 
+data interchange, it's not recommended. (Cf. Designing New Data Sections, 
+in Part 4.)
+
+Alignment
+
+All data objects larger than a byte are aligned on even byte addresses 
+relative to the start of the file. This may require padding. Pad bytes 
+are to be written as zeros, but don't count on that when reading.
+
+This means that every odd-length "chunk" (see below) must be padded 
+so that the next one will fall on an even boundary. Also, designers 
+of structures to be stored in chunks should include pad fields where 
+needed to align every field larger than a byte. Zeros should be stored 
+in all the pad bytes.
+
+Justification: Even-alignment causes a little extra work for files 
+that are used only on certain processors but allows 68000 programs 
+to construct and scan the data in memory and do block I/O. You just 
+add an occasional pad field to data structures that you're going to 
+block read/write or else stream read/write an extra byte. And the 
+same source code works on all processors. Unspecified alignment, on 
+the other hand, would force 68000 programs to (dis)assemble word and 
+long-word data one byte at a time. Pretty cumbersome in a high level 
+language. And if you don't conditionally compile that out for other 
+processors, you won't gain anything.
+
+Numbers
+
+Numeric types supported are two's complement binary integers in the 
+format used by the MC68000 processor high byte first, high word first the 
+reverse of 8088 and 6502 format. They could potentially include signed 
+and unsigned 8, 16, and 32 bit integers but the standard only uses 
+the following:
+
+UBYTE	 8 bits unsigned
+WORD	16 bits signed
+UWORD	16 bits unsigned
+LONG	32 bits signed
+
+The actual type definitions depend on the CPU and the compiler. In 
+this document, we'll express data type definitions in the C programming 
+language. [See C, A Reference Manual.] In 68000 Lattice C:
+
+typedef unsigned char	UBYTE;	/*  8 bits unsigned	*/
+typedef short	WORD;	/* 16 bits signed	*/
+typedef unsigned short	UWORD;	/* 16 bits unsigned	*/
+typedef long	LONG;	/* 32 bits signed	*/
+
+Characters
+
+The following character set is assumed wherever characters are used, 
+e.g. in text strings, IDs, and TEXT chunks (see below).
+
+Characters are encoded in 8-bit ASCII. Characters in the range NUL 
+(hex 0) through DEL (hex 7F) are well defined by the 7-bit ASCII standard. 
+IFF uses the graphic group RJS (SP, hex 20) through R~S (hex 7E).
+
+Most of the control character group hex 01 through hex 1F have no 
+standard meaning in IFF. The control character LF (hex 0A) is defined 
+as a "newline" character. It denotes an intentional line break, that 
+is, a paragraph or line terminator. (There is no way to store an automatic 
+line break. That is strictly a function of the margins in the environment 
+the text is placed.) The control character ESC (hex 1B) is a reserved 
+escape character under the rules of ANSI standard 3.64-1979 American 
+National Standard Additional Control Codes for Use with ASCII, ISO 
+standard 2022, and ISO/DIS standard 6429.2.
+
+Characters in the range hex 7F through hex FF are not globally defined 
+in IFF. They are best left reserved for future standardization. But 
+note that the FORM type FTXT (formatted text) defines the meaning 
+of these characters within FTXT forms. In particular, character values 
+hex 7F through hex 9F are control codes while characters hex A0 through 
+hex FF are extended graphic characters like  , as per the ISO and 
+ANSI standards cited above. [See the supplementary document "FTXT" 
+IFF Formatted Text.]
+
+Dates
+
+A "creation date" is defined as the date and time a stream of data 
+bytes was created. (Some systems call this a "last modified date".) 
+Editing some data changes its creation date. Moving the data between 
+volumes or machines does not.
+
+The IFF standard date format will be one of those used in MS-DOS, 
+Macintosh, or Amiga DOS (probably a 32-bit unsigned number of seconds 
+since a reference point). Issue: Investigate these three.
+
+Type IDs
+
+A "type ID", "property name", "FORM type", or any other IFF identifier 
+is a 32-bit value: the concatenation of four ASCII characters in the 
+range R S (SP, hex 20) through R~S (hex 7E). Spaces (hex 20) should 
+not precede printing characters; trailing spaces are ok. Control characters 
+are forbidden.
+
+typedef CHAR ID[4];
+
+IDs are compared using a simple 32-bit case-dependent equality test.
+
+Data section type IDs (aka FORM types) are restriced IDs. (Cf. Data 
+Sections.) Since they may be stored in filename extensions (Cf. Single 
+Purpose Files) lower case letters and punctuation marks are forbidden. 
+Trailing spaces are ok.
+
+Carefully choose those four characters when you pick a new ID. Make 
+them mnemonic so programmers can look at an interchange format file 
+and figure out what kind of data it contains. The name space makes 
+it possible for developers scattered around the globe to generate 
+ID values with minimal collisions so long as they choose specific 
+names like "MUS4" instead of general ones like "TYPE" and "FILE". 
+EA will "register" new FORM type IDs and format descriptions as they're 
+devised, but collisions will be improbable so there will be no pressure 
+on this "clearinghouse" process. Appendix A has a list of currently 
+defined IDs.
+
+Sometimes it's necessary to make data format changes that aren't backward 
+compatible. Since IDs are used to denote data formats in IFF, new 
+IDs are chosen to denote revised formats. Since programs won't read 
+chunks whose IDs they don't recognize (see Chunks, below), the new 
+IDs keep old programs from stumbling over new data. The conventional 
+way to chose a "revision" ID is to increment the last character if 
+it's a digit or else change the last character to a digit. E.g. first 
+and second revisions of the ID "XY" would be "XY1" and "XY2". Revisions 
+of "CMAP" would be "CMA1" and "CMA2".
+
+Chunks
+
+Chunks are the building blocks in the IFF structure. The form expressed 
+as a C typedef is:
+
+typedef struct {
+	ID	ckID;
+	LONG	ckSize;	/* sizeof(ckData) */
+	UBYTE	ckData[/* ckSize */];
+	} Chunk;
+
+We can diagram an example chunk a "CMAP" chunk containing 12 data 
+bytes like this:
+			----------------
+		ckID:	|    'CMAP'    |
+		ckSize: |      12      |
+		ckData: | 0, 0, 0, 32  |   -------- 
+			| 0, 0, 64, 0  |    12 bytes
+			| 0, 0, 64, 0  |   ---------
+			----------------
+
+The fixed header part means "Here's a type ckID chunk with ckSize 
+bytes of data."
+
+The ckID identifies the format and purpose of the chunk. As a rule, 
+a program must recognize ckID to interpret ckData. It should skip 
+over all unrecognized chunks. The ckID also serves as a format version 
+number as long as we pick new IDs to identify new formats of ckData 
+(see above).
+
+The following ckIDs are universally reserved to identify chunks with 
+particular IFF meanings: "LIST", "FORM", "PROP", "CAT ", and "    
+". The special ID "    " (4 spaces) is a ckID for "filler" chunks, 
+that is, chunks that fill space but have no meaningful contents. The 
+IDs "LIS1" through "LIS9", "FOR1" through "FOR9", and "CAT1" through 
+"CAT9" are reserved for future "version number" variations. All IFF-compatible 
+software must account for these 23 chunk IDs. Appendix A has a list 
+of predefined IDs.
+
+The ckSize is a logical block size how many data bytes are in ckData. 
+If ckData is an odd number of bytes long, a 0 pad byte follows which 
+is not included in ckSize. (Cf. Alignment.) A chunk's total physical 
+size is ckSize rounded up to an even number plus the size of the header. 
+So the smallest chunk is 8 bytes long with ckSize = 0. For the sake 
+of following chunks, programs must respect every chunk's ckSize as 
+a virtual end-of-file for reading its ckData even if that data is 
+malformed, e.g. if nested contents are truncated.
+
+We can describe the syntax of a chunk as a regular expression with 
+"#" representing the ckSize, i.e. the length of the following {braced} 
+bytes. The "[0]" represents a sometimes needed pad byte. (The regular 
+expressions in this document are collected in Appendix A along with 
+an explanation of notation.)
+
+Chunk	::= ID #{ UBYTE* } [0]
+
+One chunk output technique is to stream write a chunk header, stream 
+write the chunk contents, then random access back to the header to 
+fill in the size. Another technique is to make a preliminary pass 
+over the data to compute the size, then write it out all at once.
+
+Strings, String Chunks, and String Properties
+
+In a string of ASCII text, LF denotes a forced line break (paragraph 
+or line terminator). Other control characters are not used. (Cf. Characters.)
+
+The ckID for a chunk that contains a string of plain, unformatted 
+text is "TEXT". As a practical matter, a text string should probably 
+not be longer than 32767 bytes. The standard allows up to 231 - 1 
+bytes.
+
+When used as a data property (see below), a text string chunk may 
+be 0 to 255 characters long. Such a string is readily converted to 
+a C string or a Pascal STRING[255]. The ckID of a property must be 
+the property name, not "TEXT".
+
+When used as a part of a chunk or data property, restricted C string 
+format is normally used. That means 0 to 255 characters followed by 
+a NUL byte (ASCII value 0).
+
+Data Properties
+
+Data properties specify attributes for following (non-property) chunks. 
+A data property essentially says "identifier = value", for example 
+"XY = (10, 200)", telling something about following chunks. Properties 
+may only appear inside data sections ("FORM" chunks, cf. Data Sections) 
+and property sections ("PROP" chunks, cf. Group PROP).
+
+The form of a data property is a special case of Chunk. The ckID is 
+a property name as well as a property type. The ckSize should be small 
+since data properties are intended to be accumulated in RAM when reading 
+a file. (256 bytes is a reasonable upper bound.) Syntactically:
+
+Property	::= Chunk
+
+When designing a data object, use properties to describe context information 
+like the size of an image, even if they don't vary in your program. 
+Other programs will need this information.
+
+Think of property settings as assignments to variables in a programming 
+language. Multiple assignments are redundant and local assignments 
+temporarily override global assignments. The order of assignments 
+doesn't matter as long as they precede the affected chunks. (Cf. LISTs, 
+CATs, and Shared Properties.)
+
+Each object type (FORM type) is a local name space for property IDs. 
+Think of a "CMAP" property in a "FORM ILBM" as the qualified ID "ILBM.CMAP". 
+Property IDs specified when an object type is designed (and therefore 
+known to all clients) are called "standard" while specialized ones 
+added later are "nonstandard".
+
+Links
+
+Issue: A standard mechanism for "links" or "cross references" is very 
+desirable for things like combining images and sounds into animations. 
+Perhaps we'll define "link" chunks within FORMs that refer to other 
+FORMs or to specific chunks within the same and other FORMs. This 
+needs further work. EA IFF 1985 has no standard link mechanism.
+
+For now, it may suffice to read a list of, say, musical instruments, 
+and then just refer to them within a musical score by index number.
+
+File References
+
+Issue: We may need a standard form for references to other files. 
+A "file ref" could name a directory and a file in the same type of 
+operating system as the ref's originator. Following the reference 
+would expect the file to be on some mounted volume. In a network environment, 
+a file ref could name a server, too.
+
+Issue: How can we express operating-system independent file refs?
+
+Issue: What about a means to reference a portion of another file? 
+Would this be a "file ref" plus a reference to a "link" within the 
+target file?
+
+
+
+4. Data Sections
+
+The first thing we need of a file is to check: Does it contain IFF 
+data and, if so, does it contain the kind of data we're looking for? 
+So we come to the notion of a "data section".
+
+A "data section" or IFF "FORM" is one self-contained "data object" 
+that might be stored in a file by itself. It is one high level data 
+object such as a picture or a sound effect. The IFF structure "FORM" 
+makes it self- identifying. It could be a composite object like a 
+musical score with nested musical instrument descriptions.
+
+Group FORM
+
+A data section is a chunk with ckID "FORM" and this arrangement:
+
+FORM	::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* 
+}
+FormType	::= ID
+LocalChunk	::= Property | Chunk
+
+The ID "FORM" is a syntactic keyword like "struct" in C. Think of 
+a "struct ILBM" containing a field "CMAP". If you see "FORM" you'll 
+know to expect a FORM type ID (the structure name, "ILBM" in this 
+example) and a particular contents arrangement or "syntax" (local 
+chunks, FORMs, LISTs, and CATs). (LISTs and CATs are discussed in 
+part 5, below.) A "FORM ILBM", in particular, might contain a local 
+chunk "CMAP", an "ILBM.CMAP" (to use a qualified name).
+
+So the chunk ID "FORM" indicates a data section. It implies that the 
+chunk contains an ID and some number of nested chunks. In reading 
+a FORM, like any other chunk, programs must respect its ckSize as 
+a virtual end-of-file for reading its contents, even if they're truncated.
+
+The FormType (or FORM type) is a restricted ID that may not contain 
+lower case letters or punctuation characters. (Cf. Type IDs. Cf. Single 
+Purpose Files.)
+
+The type-specific information in a FORM is composed of its "local 
+chunks": data properties and other chunks. Each FORM type is a local 
+name space for local chunk IDs. So "CMAP" local chunks in other FORM 
+types may be unrelated to "ILBM.CMAP". More than that, each FORM type 
+defines semantic scope. If you know what a FORM ILBM is, you'll know 
+what an ILBM.CMAP is.
+
+Local chunks defined when the FORM type is designed (and therefore 
+known to all clients of this type) are called "standard" while specialized 
+ones added later are "nonstandard".
+
+Among the local chunks, property chunks give settings for various 
+details like text font while the other chunks supply the essential 
+information. This distinction is not clear cut. A property setting 
+cancelled by a later setting of the same property has effect only 
+on data chunks in between. E.g. in the sequence:
+
+prop1 = x  (propN = value)*  prop1 = y
+
+where the propNs are not prop1, the setting prop1 = x has no effect.
+
+The following universal chunk IDs are reserved inside any FORM: "LIST", 
+"FORM", "PROP", "CAT ", "JJJJ", "LIS1" through "LIS9", "FOR1" through 
+"FOR9", and "CAT1" through "CAT9". (Cf. Chunks. Cf. Group LIST. Cf. 
+Group PROP.) For clarity, these universal chunk names may not be FORM 
+type IDs, either.
+
+Part 5, below, talks about grouping FORMs into LISTs and CATs. They 
+let you group a bunch of FORMs but don't impose any particular meaning 
+or constraints on the grouping. Read on.
+
+Composite FORMs
+
+A FORM chunk inside a FORM is a full-fledged data section. This means 
+you can build a composite object like a multi-frame animation sequence 
+from available picture FORMs and sound effect FORMs. You can insert 
+additional chunks with information like frame rate and frame count.
+
+Using composite FORMs, you leverage on existing programs that create 
+and edit the component FORMs. Those editors may even look into your 
+composite object to copy out its type of component, although it'll 
+be the rare program that's fancy enough to do that. Such editors are 
+not allowed to replace their component objects within your composite 
+object. That's because the IFF standard lets you specify consistency 
+requirements for the composite FORM such as maintaining a count or 
+a directory of the components. Only programs that are written to uphold 
+the rules of your FORM type should create or modify such FORMs.
+
+Therefore, in designing a program that creates composite objects, 
+you are strongly requested to provide a facility for your users to 
+import and export the nested FORMs. Import and export could move the 
+data through a clipboard or a file.
+
+Here are several existing FORM types and rules for defining new ones.
+
+FTXT
+
+An FTXT data section contains text with character formatting information 
+like fonts and faces. It has no paragraph or document formatting information 
+like margins and page headers. FORM FTXT is well matched to the text 
+representation in Amiga's Intuition environment. See the supplemental 
+document "FTXT" IFF Formatted Text.
+
+ILBM
+
+"ILBM" is an InterLeaved BitMap image with color map; a machine-independent 
+format for raster images. FORM ILBM is the standard image file format 
+for the Commodore-Amiga computer and is useful in other environments, 
+too. See the supplemental document "ILBM" IFF Interleaved Bitmap.
+
+PICS
+
+The data chunk inside a "PICS" data section has ID "PICT" and holds 
+a QuickDraw picture. Issue: Allow more than one PICT in a PICS? See 
+Inside Macintosh chapter "QuickDraw" for details on PICTs and how 
+to create and display them on the Macintosh computer.
+
+The only standard property for PICS is "XY", an optional property 
+that indicates the position of the PICT relative to "the big picture". 
+The contents of an XY is a QuickDraw Point.
+
+Note: PICT may be limited to Macintosh use, in which case there'll 
+be another format for structured graphics in other environments.
+
+Other Macintosh Resource Types
+
+Some other Macintosh resource types could be adopted for use within 
+IFF files; perhaps MWRT, ICN, ICN#, and STR#.
+
+Issue: Consider the candidates and reserve some more IDs.
+
+Designing New Data Sections
+
+Supplemental documents will define additional object types. A supplement 
+needs to specify the object's purpose, its FORM type ID, the IDs and 
+formats of standard local chunks, and rules for generating and interpreting 
+the data. It's a good idea to supply typedefs and an example source 
+program that accesses the new object. See "ILBM" IFF Interleaved Bitmap 
+for a good example.
+
+Anyone can pick a new FORM type ID but should reserve it with Electronic 
+Arts at their earliest convenience. [Issue: EA contact person? Hand 
+this off to another organization?] While decentralized format definitions 
+and extensions are possible in IFF, our preference is to get design 
+consensus by committee, implement a program to read and write it, 
+perhaps tune the format, and then publish the format with example 
+code. Some organization should remain in charge of answering questions 
+and coordinating extensions to the format.
+
+If it becomes necessary to revise the design of some data section, 
+its FORM type ID will serve as a version number (Cf. Type IDs). E.g. 
+a revised "VDEO" data section could be called "VDE1". But try to get 
+by with compatible revisions within the existing FORM type.
+
+In a new FORM type, the rules for primitive data types and word-alignment 
+(Cf. Primitive Data Types) may be overriden for the contents of its 
+local chunks but not for the chunk structure itself if your documentation 
+spells out the deviations. If machine-specific type variants are needed, 
+e.g. to store vast numbers of integers in reverse bit order, then 
+outline the conversion algorithm and indicate the variant inside each 
+file, perhaps via different FORM types. Needless to say, variations 
+should be minimized.
+
+In designing a FORM type, encapsulate all the data that other programs 
+will need to interpret your files. E.g. a raster graphics image should 
+specify the image size even if your program always uses 320 x 200 
+pixels x 3 bitplanes. Receiving programs are then empowered to append 
+or clip the image rectangle, to add or drop bitplanes, etc. This enables 
+a lot more compatibility.
+
+Separate the central data (like musical notes) from more specialized 
+information (like note beams) so simpler programs can extract the 
+central parts during read-in. Leave room for expansion so other programs 
+can squeeze in new kinds of information (like lyrics). And remember 
+to keep the property chunks manageably short let's say 2 256 bytes.
+
+When designing a data object, try to strike a good tradeoff between 
+a super-general format and a highly-specialized one. Fit the details 
+to at least one particular need, for example a raster image might 
+as well store pixels in the current machine's scan order. But add 
+the kind of generality that makes it usable with foreseeable hardware 
+and software. E.g. use a whole byte for each red, green, and blue 
+color value even if this year's computer has only 4-bit video DACs. 
+Think ahead and help other programs so long as the overhead is acceptable. 
+E.g. run compress a raster by scan line rather than as a unit so future 
+programs can swap images by scan line to and from secondary storage.
+
+Try to design a general purpose "least common multiple" format that 
+encompasses the needs of many programs without getting too complicated. 
+Let's coalesce our uses around a few such formats widely separated 
+in the vast design space. Two factors make this flexibility and simplicity 
+practical. First, file storage space is getting very plentiful, so 
+compaction is not a priority. Second, nearly any locally-performed 
+data conversion work during file reading and writing will be cheap 
+compared to the I/O time.
+
+It must be ok to copy a LIST or FORM or CAT intact, e.g. to incorporate 
+it into a composite FORM. So any kind of internal references within 
+a FORM must be relative references. They could be relative to the 
+start of the containing FORM, relative from the referencing chunk, 
+or a sequence number into a collection.
+
+With composite FORMs, you leverage on existing programs that create 
+and edit the components. If you write a program that creates composite 
+objects, please provide a facility for your users to import and export 
+the nested FORMs. The import and export functions may move data through 
+a separate file or a clipboard.
+
+Finally, don't forget to specify all implied rules in detail.
+
+
+
+5. LISTs, CATs, and Shared Properties
+
+Data often needs to be grouped together like a list of icons. Sometimes 
+a trick like arranging little images into a big raster works, but 
+generally they'll need to be structured as a first class group. The 
+objects "LIST" and "CAT" are IFF-universal mechanisms for this purpose.
+
+Property settings sometimes need to be shared over a list of similar 
+objects. E.g. a list of icons may share one color map. LIST provides 
+a means called "PROP" to do this. One purpose of a LIST is to define 
+the scope of a PROP. A "CAT", on the other hand, is simply a concatenation 
+of objects.
+
+Simpler programs may skip LISTs and PROPs altogether and just handle 
+FORMs and CATs. All "fully-conforming" IFF programs also know about 
+"CAT ", "LIST", and "PROP". Any program that reads a FORM inside a 
+LIST must process shared PROPs to correctly interpret that FORM.
+
+Group CAT
+
+A CAT is just an untyped group of data objects.
+
+Structurally, a CAT is a chunk with chunk ID "CAT " containing a "contents 
+type" ID followed by the nested objects. The ckSize of each contained 
+chunk is essentially a relative pointer to the next one.
+
+CAT	::= "CAT " #{ ContentsType (FORM | LIST | CAT)* }
+ContentsType	::= ID	-- a hint or an "abstract data type" ID
+
+In reading a CAT, like any other chunk, programs must respect it's 
+ckSize as a virtual end-of-file for reading the nested objects even 
+if they're malformed or truncated.
+
+The "contents type" following the CAT's ckSize indicates what kind 
+of FORMs are inside. So a CAT of ILBMs would store "ILBM" there. It's 
+just a hint. It may be used to store an "abstract data type". A CAT 
+could just have blank contents ID ("JJJJ") if it contains more than 
+one kind of FORM.
+
+CAT defines only the format of the group. The group's meaning is open 
+to interpretation. This is like a list in LISP: the structure of cells 
+is predefined but the meaning of the contents as, say, an association 
+list depends on use. If you need a group with an enforced meaning 
+(an "abstract data type" or Smalltalk "subclass"), some consistency 
+constraints, or additional data chunks, use a composite FORM instead 
+(Cf. Composite FORMs).
+
+Since a CAT just means a concatenation of objects, CATs are rarely 
+nested. Programs should really merge CATs rather than nest them.
+
+Group LIST
+
+A LIST defines a group very much like CAT but it also gives a scope 
+for PROPs (see below). And unlike CATs, LISTs should not be merged 
+without understanding their contents.
+
+Structurally, a LIST is a chunk with ckID "LIST" containing a "contents 
+type" ID, optional shared properties, and the nested contents (FORMs, 
+LISTs, and CATs), in that order. The ckSize of each contained chunk 
+is a relative pointer to the next one. A LIST is not an arbitrary 
+linked list the cells are simply concatenated.
+
+LIST	::= "LIST" #{ ContentsType PROP* (FORM | LIST | CAT)* }
+ContentsType	::= ID
+
+Group PROP
+
+PROP chunks may appear in LISTs (not in FORMs or CATs). They supply 
+shared properties for the FORMs in that LIST. This ability to elevate 
+some property settings to shared status for a list of forms is useful 
+for both indirection and compaction. E.g. a list of images with the 
+same size and colors can share one "size" property and one "color 
+map" property. Individual FORMs can override the shared settings.
+
+The contents of a PROP is like a FORM with no data chunks:
+
+PROP	::= "PROP" #{ FormType Property* }
+
+It means, "Here are the shared properties for FORM type <<FormType>."
+
+A LIST may have at most one PROP of a FORM type, and all the PROPs 
+must appear before any of the FORMs or nested LISTs and CATs. You 
+can have subsequences of FORMs sharing properties by making each subsequence 
+a LIST.
+
+Scoping: Think of property settings as variable bindings in nested 
+blocks of a programming language. Where in C you could write:
+
+TEXT_FONT text_font = Courier;	/* program's global default	*/
+
+File(); {
+	TEXT_FONT text_font = TimesRoman;	/* shared setting	*/
+
+		{
+		TEXT_FONT text_font = Helvetica;  /* local setting	*/
+		Print("Hello ");	/* uses font Helvetica	*/
+		}
+
+		{
+		Print("there.");	/* uses font TimesRoman	*/
+		}
+	}
+
+An IFF file could contain:
+
+LIST {
+	PROP TEXT {
+		FONT {TimesRoman}	/* shared setting	*/
+		}
+
+	FORM TEXT {
+		FONT {Helvetica}	/* local setting	*/
+		CHRS {Hello }		/* uses font Helvetica	*/
+		}
+
+	FORM TEXT {
+		CHRS {there.}	/* uses font TimesRoman	*/
+		}
+	}
+
+The shared property assignments selectively override the reader's 
+global defaults, but only for FORMs within the group. A FORM's own 
+property assignments selectively override the global and group-supplied 
+values. So when reading an IFF file, keep property settings on a stack. 
+They're designed to be small enough to hold in main memory.
+
+Shared properties are semantically equivalent to copying those properties 
+into each of the nested FORMs right after their FORM type IDs.
+
+Properties for LIST
+
+Optional "properties for LIST" store the origin of the list's contents 
+in a PROP chunk for the fake FORM type "LIST". They are the properties 
+originating program "OPGM", processor family "OCPU", computer type 
+"OCMP", computer serial number or network address "OSN ", and user 
+name "UNAM". In our imperfect world, these could be called upon to 
+distinguish between unintended variations of a data format or to work 
+around bugs in particular originating/receiving program pairs. Issue: 
+Specify the format of these properties.
+
+A creation date could also be stored in a property but let's ask that 
+file creating, editing, and transporting programs maintain the correct 
+date in the local file system. Programs that move files between machine 
+types are expected to copy across the creation dates.
+
+
+
+6. Standard File Structure
+
+File Structure Overview
+
+An IFF file is just a single chunk of type FORM, LIST, or CAT. Therefore 
+an IFF file can be recognized by its first 4 bytes: "FORM", "LIST", 
+or "CAT ". Any file contents after the chunk's end are to be ignored.
+
+Since an IFF file can be a group of objects, programs that read/write 
+single objects can communicate to an extent with programs that read/write 
+groups. You're encouraged to write programs that handle all the objects 
+in a LIST or CAT. A graphics editor, for example, could process a 
+list of pictures as a multiple page document, one page at a time.
+
+Programs should enforce IFF's syntactic rules when reading and writing 
+files. This ensures robust data transfer. The public domain IFF reader/writer 
+subroutine package does this for you. A utility program "IFFCheck" 
+is available that scans an IFF file and checks it for conformance 
+to IFF's syntactic rules. IFFCheck also prints an outline of the chunks 
+in the file, showing the ckID and ckSize of each. This is quite handy 
+when building IFF programs. Example programs are also available to 
+show details of reading and writing IFF files.
+
+A merge program "IFFJoin" will be available that logically appends 
+IFF files into a single CAT group. It "unwraps" each input file that 
+is a CAT so that the combined file isn't nested CATs.
+
+If we need to revise the IFF standard, the three anchoring IDs will 
+be used as "version numbers". That's why IDs "FOR1" through "FOR9", 
+"LIS1" through "LIS9", and "CAT1" through "CAT9" are reserved.
+
+IFF formats are designed for reasonable performance with floppy disks. 
+We achieve considerable simplicity in the formats and programs by 
+relying on the host file system rather than defining universal grouping 
+structures like directories for LIST contents. On huge storage systems, 
+IFF files could be leaf nodes in a file structure like a B-tree. Let's 
+hope the host file system implements that for us!
+
+Thre are two kinds of IFF files: single purpose files and scrap files. 
+They differ in the interpretation of multiple data objects and in 
+the file's external type.
+
+Single Purpose Files
+
+A single purpose IFF file is for normal "document" and "archive" storage. 
+This is in contrast with "scrap files" (see below) and temporary backing 
+storage (non-interchange files).
+
+The external file type (or filename extension, depending on the host 
+file system) indicates the file's contents. It's generally the FORM 
+type of the data contained, hence the restrictions on FORM type IDs.
+
+Programmers and users may pick an "intended use" type as the filename 
+extension to make it easy to filter for the relevant files in a filename 
+requestor. This is actually a "subclass" or "subtype" that conveniently 
+separates files of the same FORM type that have different uses. Programs 
+cannot demand conformity to its expected subtypes without overly restricting 
+data interchange since they cannot know about the subtypes to be used 
+by future programs that users will want to exchange data with.
+
+Issue: How to generate 3-letter MS-DOS extensions from 4-letter FORM 
+type IDs?
+
+Most single purpose files will be a single FORM (perhaps a composite 
+FORM like a musical score containing nested FORMs like musical instrument 
+descriptions). If it's a LIST or a CAT, programs should skip over 
+unrecognized objects to read the recognized ones or the first recognized 
+one. Then a program that can read a single purpose file can read something 
+out of a "scrap file", too.
+
+Scrap Files
+
+A "scrap file" is for maximum interconnectivity in getting data between 
+programs; the core of a clipboard function. Scrap files may have type 
+"IFF " or filename extension ".IFF".
+
+A scrap file is typically a CAT containing alternate representations 
+of the same basic information. Include as many alternatives as you 
+can readily generate. This redundancy improves interconnectivity in 
+situations where we can't make all programs read and write super-general 
+formats. [Inside Macintosh chapter "Scrap Manager".] E.g. a graphically-
+annotated musical score might be supplemented by a stripped down 4-voice 
+melody and by a text (the lyrics).
+
+The originating program should write the alternate representations 
+in order of "preference": most preferred (most comprehensive) type 
+to least preferred (least comprehensive) type. A receiving program 
+should either use the first appearing type that it understands or 
+search for its own "preferred" type.
+
+A scrap file should have at most one alternative of any type. (A LIST 
+of same type objects is ok as one of the alternatives.) But don't 
+count on this when reading; ignore extra sections of a type. Then 
+a program that reads scrap files can read something out of single 
+purpose files.
+
+Rules for Reader Programs
+
+Here are some notes on building programs that read IFF files. If you 
+use the standard IFF reader module "IFFR.C", many of these rules and 
+details will be automatically handled. (See "Support Software" in 
+Appendix A.) We recommend that you start from the example program 
+"ShowILBM.C". You should also read up on recursive descent parsers. 
+[See, for example, Compiler Construction, An Advanced Course.]
+
+%	The standard is very flexible so many programs can exchange 
+data. This implies a program has to scan the file and react to what's 
+actually there in whatever order it appears. An IFF reader program 
+is a parser.
+
+%	For interchange to really work, programs must be willing to 
+do some conversion during read-in. If the data isn't exactly what 
+you expect, say, the raster is smaller than those created by your 
+program, then adjust it. Similarly, your program could crop a large 
+picture, add or drop bitplanes, and create/discard a mask plane. The 
+program should give up gracefully on data that it can't convert.
+
+%	If it doesn't start with "FORM", "LIST", or "CAT ", it's not 
+an IFF-85 file.
+
+%	For any chunk you encounter, you must recognize its type ID 
+to understand its contents.
+
+%	For any FORM chunk you encounter, you must recognize its FORM 
+type ID to understand the contained "local chunks". Even if you don't 
+recognize the FORM type, you can still scan it for nested FORMs, LISTs, 
+and CATs of interest.
+
+%	Don't forget to skip the pad byte after every odd-length chunk.
+
+%	Chunk types LIST, FORM, PROP, and CAT are generic groups. They 
+always contain a subtype ID followed by chunks.
+
+%	Readers ought to handle a CAT of FORMs in a file. You may treat 
+the FORMs like document pages to sequence through or just use the 
+first FORM.
+
+%	Simpler IFF readers completely skip LISTs. "Fully IFF-conforming" 
+readers are those that handle LISTs, even if just to read the first 
+FORM from a file. If you do look into a LIST, you must process shared 
+properties (in PROP chunks) properly. The idea is to get the correct 
+data or none at all.
+
+%	The nicest readers are willing to look into unrecognized FORMs 
+for nested FORM types that they do recognize. For example, a musical 
+score may contain nested instrument descriptions and an animation 
+file may contain still pictures.
+
+Note to programmers: Processing PROP chunks is not simple! You'll 
+need some background in interpreters with stack frames. If this is 
+foreign to you, build programs that read/write only one FORM per file. 
+For the more intrepid programmers, the next paragraph summarizes how 
+to process LISTs and PROPs. See the general IFF reader module "IFFR.C" 
+and the example program "ShowILBM.C" for details.
+
+Allocate a stack frame for every LIST and FORM you encounter and initialize 
+it by copying the stack frame of the parent LIST or FORM. At the top 
+level, you'll need a stack frame initialized to your program's global 
+defaults. While reading each LIST or FORM, store all encountered properties 
+into the current stack frame. In the example ShowILBM, each stack 
+frame has a place for a bitmap header property ILBM.BMHD and a color 
+map property ILBM.CMAP. When you finally get to the ILBM's BODY chunk, 
+use the property settings accumulated in the current stack frame.
+
+An alternate implementation would just remember PROPs encountered, 
+forgetting each on reaching the end of its scope (the end of the containing 
+LIST). When a FORM XXXX is encountered, scan the chunks in all remembered 
+PROPs XXXX, in order, as if they appeared before the chunks actually 
+in the FORM XXXX. This gets trickier if you read FORMs inside of FORMs.
+
+Rules for Writer Programs
+
+Here are some notes on building programs that write IFF files, which 
+is much easier than reading them. If you use the standard IFF writer 
+module "IFFW.C" (see "Support Software" in Appendix A), many of these 
+rules and details will automatically be enforced. See the example 
+program "Raw2ILBM.C".
+
+%	An IFF file is a single FORM, LIST, or CAT chunk.
+
+%	Any IFF-85 file must start with the 4 characters "FORM", "LIST", 
+or "CAT ", followed by a LONG ckSize. There should be no data after 
+the chunk end.
+
+%	Chunk types LIST, FORM, PROP, and CAT are generic. They always 
+contain a subtype ID followed by chunks. These three IDs are universally 
+reserved, as are "LIS1" through "LIS9", "FOR1" through "FOR9", "CAT1" 
+through "CAT9", and "    ".
+
+%	Don't forget to write a 0 pad byte after each odd-length chunk.
+
+%	Four techniques for writing an IFF group: (1) build the data 
+in a file mapped into virtual memory, (2) build the data in memory 
+blocks and use block I/O, (3) stream write the data piecemeal and 
+(don't forget!) random access back to set the group length count, 
+and (4) make a preliminary pass to compute the length count then stream 
+write the data.
+
+%	Do not try to edit a file that you don't know how to create. 
+Programs may look into a file and copy out nested FORMs of types that 
+they recognize, but don't edit and replace the nested FORMs and don't 
+add or remove them. That could make the containing structure inconsistent. 
+You may write a new file containing items you copied (or copied and 
+modified) from another IFF file, but don't copy structural parts you 
+don't understand.
+
+%	You must adhere to the syntax descriptions in Appendex A. E.g. 
+PROPs may only appear inside LISTs.
+
+
+
+
+Appendix A. Reference
+
+Type Definitions
+
+The following C typedefs describe standard IFF structures. Declarations 
+to use in practice will vary with the CPU and compiler. For example, 
+68000 Lattice C produces efficient comparison code if we define ID 
+as a "LONG". A macro "MakeID" builds these IDs at compile time.
+
+/* Standard IFF types, expressed in 68000 Lattice C.	*/
+
+typedef unsigned char UBYTE;	/*  8 bits unsigned	*/
+typedef short WORD;	/* 16 bits signed	*/
+typedef unsigned short UWORD;	/* 16 bits unsigned	*/
+typedef long LONG;	/* 32 bits signed	*/
+
+typedef char ID[4];	/* 4 chars in ' ' through '~'	*/
+
+typedef struct {
+	ID	ckID;
+	LONG	ckSize;	/* sizeof(ckData)	*/
+	UBYTE	ckData[/* ckSize */];
+	} Chunk;
+
+/* ID typedef and builder for 68000 Lattice C. */
+typedef LONG ID; 	/* 4 chars in ' ' through '~'	*/
+#define MakeID(a,b,c,d) ( (a)<<<<24 | (b)<<<<16 | (c)<<<<8 | (d) )
+
+/* Globally reserved IDs. */
+#define ID_FORM   MakeID('F','O','R','M')
+#define ID_LIST   MakeID('L','I','S','T')
+#define ID_PROP   MakeID('P','R','O','P')
+#define ID_CAT    MakeID('C','A','T',' ')
+#define ID_FILLER MakeID(' ',' ',' ',' ')
+
+Syntax Definitions
+
+Here's a collection of the syntax definitions in this document.
+
+Chunk	::= ID #{ UBYTE* } [0]
+
+Property	::= Chunk
+
+FORM	::= "FORM" #{ FormType (LocalChunk | FORM | LIST | CAT)* 
+}
+FormType	::= ID
+LocalChunk	::= Property | Chunk
+
+CAT	::= "CAT " #{ ContentsType (FORM | LIST | CAT)* }
+ContentsType	::= ID	-- a hint or an "abstract data type" ID
+
+LIST	::= "LIST" #{ ContentsType PROP* (FORM | LIST | CAT)* }
+PROP	::= "PROP" #{ FormType Property* }
+
+In this extended regular expression notation, the token "#" represents 
+a ckSize LONG count of the following {braced} data bytes. Literal 
+items are shown in "quotes", [square bracketed items] are optional, 
+and "*" means 0 or more instances. A sometimes-needed pad byte is 
+shown as "[0]".
+
+Defined Chunk IDs
+
+This is a table of currently defined chunk IDs. We may also borrow 
+some Macintosh IDs and data formats.
+
+Group chunk IDs
+	FORM, LIST, PROP, CAT.
+Future revision group chunk IDs
+	FOR1 I FOR9, LIS1 I LIS9, CAT1 I CAT9.
+FORM type IDs
+	(The above group chunk IDs may not be used for FORM type IDs.)
+	(Lower case letters and punctuation marks are forbidden in FORM 
+type IDs.)
+	8SVX 8-bit sampled sound voice, ANBM animated bitmap, FNTR raster 
+font, FNTV vector font, FTXT formatted text, GSCR general-use musical 
+score, ILBM interleaved raster bitmap image, PDEF Deluxe Print page 
+definition, PICS Macintosh picture, PLBM (obsolete), USCR Uhuru Sound 
+Software musical score, UVOX Uhuru Sound Software Macintosh voice, 
+SMUS simple musical score, VDEO Deluxe Video Construction Set video.
+Data chunk IDs
+	"JJJJ", TEXT, PICT.
+PROP LIST property IDs
+	OPGM, OCPU, OCMP, OSN, UNAM.
+
+
+
+Support Software
+
+These public domain C source programs are available for use in building 
+IFF-compatible programs:
+
+IFF.H, IFFR.C, IFFW.C	
+
+		IFF reader and writer package. 
+		These modules handle many of the details of reliably 
+		reading and writing IFF files.
+
+IFFCheck.C	This handy utility program scans an IFF file, checks 
+		that the contents are well formed, and prints an outline 
+		of the chunks.
+
+PACKER.H, Packer.C, UnPacker.C	
+
+		Run encoder and decoder used for ILBM files.
+
+ILBM.H, ILBMR.C, ILBMW.C	
+
+		Reader and writer support routines for raster image 
+		FORM ILBM. ILBMR calls IFFR and UnPacker. ILBMW calls 
+		IFFW and Packer.
+
+ShowILBM.C	
+		Example caller of IFFR and ILBMR modules. This 
+		Commodore-Amiga program reads and displays a FORM ILBM.
+Raw2ILBM.C	
+		Example ILBM writer program. As a demonstration, it 
+		reads a raw raster image file and writes the image 
+		as a FORM ILBM file.
+ILBM2Raw.C	
+		Example ILBM reader program.  Reads a FORM ILBM file
+		and writes it into a raw raster image.
+
+REMALLOC.H, Remalloc.c
+
+		Memory allocation routines used in these examples.
+
+INTUALL.H	generic "include almost everything" include-file
+		with the sequence of includes correctly specified.
+
+READPICT.H, ReadPict.c	
+
+		given an ILBM file, read it into a bitmap and 
+		a color map
+
+PUTPICT.H, PutPict.c 	
+
+		given a bitmap and a color map, save it as
+		an ILBM file.
+
+GIO.H, Gio.c	generic I/O speedup package.  Attempts to speed
+		disk I/O by buffering writes and reads.
+
+giocall.c	sample call to gio.
+
+ilbmdump.c	reads in ILBM file, prints out ascii representation
+		for including in C files.
+
+bmprintc.c	prints out a C-language representation of data for
+		a bitmap.
+
+
+
+Example Diagrams
+
+Here's a box diagram for an example IFF file, a raster image FORM 
+ILBM. This FORM contains a bitmap header property chunk BMHD, a color 
+map property chunk CMAP, and a raster data chunk BODY. This particular 
+raster is 320 x 200 pixels x 3 bit planes uncompressed. The "0" after 
+the CMAP chunk represents a zero pad byte; included since the CMAP 
+chunk has an odd length. The text to the right of the diagram shows 
+the outline that would be printed by the IFFCheck utility program 
+for this particular file.
+
+	+-----------------------------------+
+	|'FORM'		24070		    |	FORM 24070 IBLM
+	+-----------------------------------+
+	|'ILBM'				    |
+	+-----------------------------------+
+	| +-------------------------------+ |
+	| | 'BMHD'	20		  | |	.BMHD  20
+	| | 320, 200, 0, 0, 3, 0, 0, ...  | |
+	| + ------------------------------+ |
+	| | 'CMAP'	21	          | |	.CMAP  21
+	| | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |
+	| +-------------------------------+ |
+	| 0				    |
+	+-----------------------------------+
+	|'BODY'		24000		    |	.BODY 24000
+	|0, 0, 0, ...			    |
+	+-----------------------------------+
+
+This second diagram shows a LIST of two FORMs ILBM sharing a common 
+BMHD property and a common CMAP property. Again, the text on the right 
+is an outline  a la IFFCheck.
+
+
+     +-----------------------------------------+
+     |'LIST'		48114	       	       |  LIST  48114  AAAA
+     +-----------------------------------------+
+     |'AAAA'				       |  .PROP  62  ILBM
+     |	+-----------------------------------+  |
+     |  |'PROP'		62		    |  |  
+     |  +-----------------------------------+  |
+     |	|'ILBM'				    |  |
+     |	+-----------------------------------+  |
+     |	| +-------------------------------+ |  |
+     |	| | 'BMHD'	20		  | |  |  ..BMHD  20
+     |	| | 320, 200, 0, 0, 3, 0, 0, ...  | |  |
+     |	| | ------------------------------+ |  |
+     |	| | 'CMAP'	21	          | |  |  ..CMAP  21
+     |	| | 0, 0, 0; 32, 0, 0; 64,0,0; .. | |  |
+     |	| +-------------------------------+ |  |
+     |	| 0				    |  |
+     |	+-----------------------------------+  |
+     |	+-----------------------------------+  |
+     |	|'FORM'		24012		    |  |  .FORM  24012  ILBM
+     |	+-----------------------------------+  |
+     |	|'ILBM'				    |  |  
+     |	+-----------------------------------+  |
+     |	|  +-----------------------------+  |  |
+     |	|  |'BODY'		24000    |  |  |  ..BODY  24000
+     |	|  |0, 0, 0, ...		 |  |  |
+     |	|  +-----------------------------+  |  |
+     |	+-----------------------------------+  |
+     |	+-----------------------------------+  |
+     |	|'FORM'		24012		    |  |  .FORM  24012  ILBM
+     |	+-----------------------------------+  |
+     |	|'ILBM'				    |  |
+     |	+-----------------------------------+  |
+     |	|  +-----------------------------+  |  |
+     |	|  |'BODY'		24000    |  |  |  ..BODY  24000
+     |	|  |0, 0, 0, ...		 |  |  |
+     |	|  +-----------------------------+  |  |
+     |	+-----------------------------------+  |
+     +-----------------------------------------+
+
+
+
+Appendix B. Standards Committee
+
+The following people contributed to the design of this IFF standard:
+
+Bob "Kodiak" Burns, Commodore-Amiga
+R. J. Mical, Commodore-Amiga
+Jerry Morrison, Electronic Arts
+Greg Riker, Electronic Arts
+Steve Shaw, Electronic Arts
+Barry Walsh, Commodore-Amiga

+ 3 - 0
ilbm.mod/libiff/doc/Makefile.am

@@ -0,0 +1,3 @@
+doc_DATA = IFF.asc
+
+EXTRA_DIST = IFF.asc

+ 100 - 0
ilbm.mod/libiff/release.nix

@@ -0,0 +1,100 @@
+{ nixpkgs ? <nixpkgs>
+, systems ? [ "i686-linux" "x86_64-linux" ]
+, buildForAmiga ? false
+, buildForWindows ? false
+, amigaosenvPath ? <amigaosenv>
+, kickstartROMFile ? null
+, baseDiskImage ? null
+, useUAE ? true
+, libiff ? { outPath = ./.; rev = 1234; }
+, officialRelease ? false
+}:
+
+let
+  pkgs = import nixpkgs {};
+  
+  version = builtins.readFile ./version;
+  
+  jobs = rec {
+    tarball =
+      with pkgs;
+
+      releaseTools.sourceTarball {
+        name = "libiff-tarball";
+        src = libiff;
+        inherit version officialRelease;
+        dontBuild = false;
+        CFLAGS = "-ansi -pedantic -Wall";
+
+        buildInputs = [ help2man ];
+      };
+      
+    build =
+      (pkgs.lib.genAttrs systems (system:
+        with import nixpkgs { inherit system; };
+        
+        releaseTools.nixBuild {
+          name = "libiff";
+          inherit version;
+          src = tarball;
+          CFLAGS = "-ansi -pedantic -Wall";
+        }
+      )) //
+      (pkgs.lib.optionalAttrs (buildForWindows) { i686-windows =
+         pkgs.dotnetenv.buildSolution {
+           name = "libiff";
+           src = ./.;
+           baseDir = "src";
+           slnFile = "libiff.sln";
+           preBuild = ''
+             sed "s/@IFF_BIG_ENDIAN@/0/" libiff/ifftypes.h.in > libiff/ifftypes.h
+           '';
+           postInstall = ''
+             mkdir -p $out/include/libiff
+             cp -v libiff/*.h $out/include/libiff
+           '';
+         };
+        }) //
+      (pkgs.lib.optionalAttrs (buildForAmiga)
+        (let
+          amigaosenv = import amigaosenvPath {
+            inherit (pkgs) stdenv fetchurl lhasa uae fsuae procps bchunk cdrtools;
+            inherit (pkgs.xorg) lndir;
+          };
+        in
+        {
+          m68k-amigaos.lib = amigaosenv.mkDerivation {
+            name = "libiff-${version}";
+            src = "${tarball}/tarballs/libiff-${version}pre1234.tar.gz";
+      
+            buildCommand = ''
+              tar xfvz $src
+              cd libiff-${version}pre1234
+              CFLAGS='-noixemul -O3' ./configure --prefix=/OUT --disable-shared
+              cd src/libiff
+              make
+              make install
+            '';
+            
+            inherit kickstartROMFile baseDiskImage useUAE;
+          };
+        
+          m68k-amigaos.tools = amigaosenv.mkDerivation {
+            name = "libiff-${version}";
+            src = "${tarball}/tarballs/libiff-${version}pre1234.tar.gz";
+      
+            buildCommand = ''
+              tar xfvz $src
+                cd libiff-${version}pre1234
+               ./configure --prefix=/OUT --disable-shared
+               make
+               make check
+               make install
+            '';
+            
+            inherit kickstartROMFile baseDiskImage useUAE;
+          };
+        }));
+  };
+in
+jobs

+ 1679 - 0
ilbm.mod/libiff/src/Doxyfile

@@ -0,0 +1,1679 @@
+# Doxyfile 1.7.3
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = libiff
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 0.1
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description for a project that appears at the top of each page and should give viewer a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = ../doc/apidox
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = YES
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this
+# tag. The format is ext=language, where ext is a file extension, and language
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even if there is only one candidate or it is obvious which candidate to choose by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. The create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the stylesheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [0,1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+# Note that a value of 0 will completely suppress the enum values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing
+# MathJax, but it is strongly recommended to install a local copy of MathJax
+# before deployment.
+
+MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a PHP enabled web server instead of at the web client
+# using Javascript. Doxygen will generate the search PHP script and index
+# file to put on the web server. The advantage of the server
+# based approach is that it scales better to large projects and allows
+# full text search. The disadvantages are that it is more difficult to setup
+# and does not have live searching capabilities.
+
+SERVER_BASED_SEARCH    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will write a font called Helvetica to the output
+# directory and reference it in all dot files that doxygen generates.
+# When you want a differently looking font you can specify the font name
+# using DOT_FONTNAME. You need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, svg, gif or svg.
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES

+ 9 - 0
ilbm.mod/libiff/src/Makefile.am

@@ -0,0 +1,9 @@
+SUBDIRS = libiff iffjoin iffpp
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libiff.pc
+
+apidox:
+	doxygen Doxyfile
+
+EXTRA_DIST = libiff.pc.in

+ 14 - 0
ilbm.mod/libiff/src/iffjoin/Makefile.am

@@ -0,0 +1,14 @@
+iffjoin.1: main.c
+	$(HELP2MAN) --output=$@ --no-info --name 'Joins an arbitrary number of IFF files into a single concatenation IFF file' --libtool ./iffjoin
+
+AM_CPPFLAGS = -DHAVE_GETOPT_H=$(HAVE_GETOPT_H)
+
+bin_PROGRAMS = iffjoin
+noinst_HEADERS = join.h
+man1_MANS = iffjoin.1
+
+iffjoin_SOURCES = main.c join.c
+iffjoin_LDADD = ../libiff/libiff.la
+iffjoin_CFLAGS = -I../libiff
+
+EXTRA_DIST = iffjoin.1

+ 87 - 0
ilbm.mod/libiff/src/iffjoin/iffjoin.vcxproj

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A1D51E9B-7E52-4E13-8735-9A1E548BAAB1}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+    <LibraryPath>$(LibraryPath)</LibraryPath>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;PACKAGE_NAME="libiff";PACKAGE_VERSION="0.1";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>$(SolutionDir)\libiff;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;libiff.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="join.c" />
+    <ClCompile Include="main.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="join.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 30 - 0
ilbm.mod/libiff/src/iffjoin/iffjoin.vcxproj.filters

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="join.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="main.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="join.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 114 - 0
ilbm.mod/libiff/src/iffjoin/join.c

@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+ 
+#include "join.h"
+#include <stdio.h>
+#include "iff.h"
+#include "chunk.h"
+#include "form.h"
+#include "cat.h"
+#include "list.h"
+#include "id.h"
+
+int IFF_join(char **inputFilenames, const unsigned int inputFilenamesLength, const char *outputFilename)
+{
+    IFF_CAT *cat = IFF_createCAT("JJJJ");
+    IFF_ID lastType;
+    int sameIds = TRUE;
+    unsigned int i;
+    int status = 0;
+    
+    for(i = 0; i < inputFilenamesLength; i++)
+    {
+	/* Open each input IFF file */
+	IFF_Chunk *chunk = IFF_read(inputFilenames[i], NULL, 0);
+	
+	/* Check whether the IFF file is valid */
+	if(chunk == NULL || !IFF_check(chunk, NULL, 0))
+	{
+	    IFF_free((IFF_Chunk*)cat, NULL, 0);
+	    return 1;
+	}
+	else
+	{
+	    /* Check whether all the form types and contents types are the same */
+	    
+	    if(sameIds)
+	    {
+		if(IFF_compareId(chunk->chunkId, "FORM") == 0)
+		{
+		    IFF_Form *form = (IFF_Form*)chunk;
+		
+		    if((i > 0) && IFF_compareId(form->formType, lastType) != 0)
+			sameIds = FALSE;
+		
+		    IFF_createId(lastType, form->formType);
+		}
+		else if(IFF_compareId(chunk->chunkId, "CAT ") == 0)
+		{
+		    IFF_CAT *cat = (IFF_CAT*)chunk;
+		    
+		    if((i > 0) && IFF_compareId(cat->contentsType, lastType) != 0)
+			sameIds = FALSE;
+		
+		    IFF_createId(lastType, cat->contentsType);
+		}
+		else if(IFF_compareId(chunk->chunkId, "LIST") == 0)
+		{
+		    IFF_List *list = (IFF_List*)chunk;
+		    
+		    if((i > 0) && IFF_compareId(list->contentsType, lastType) != 0)
+			sameIds = FALSE;
+		
+		    IFF_createId(lastType, list->contentsType);
+		}
+	    }
+	    
+	    /* Add the input IFF chunk to the concatenation */
+	    IFF_addToCAT(cat, chunk);
+	}
+    }
+    
+    /* If all form types are the same, then change the contentsType of this CAT to hint about it. Otherwise the contentsType remains 'JJJJ' */
+    if(sameIds)
+	IFF_createId(cat->contentsType, lastType);
+    
+    /* Write the resulting CAT */
+    
+    if(outputFilename == NULL)
+    {
+	/* Write the CAT to the standard output */
+	if(!IFF_writeFd(stdout, (IFF_Chunk*)cat, NULL, 0))
+	    status = 1;
+    }
+    else
+    {
+	/* Write the CAT to the specified destination filename */
+	if(!IFF_write(outputFilename, (IFF_Chunk*)cat, NULL, 0))
+	    status = 1;
+    }
+    
+    /* Free everything */
+    IFF_free((IFF_Chunk*)cat, NULL, 0);
+    
+    /* Return whether the join has succeeded */
+    return status;
+}

+ 35 - 0
ilbm.mod/libiff/src/iffjoin/join.h

@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_JOIN_H
+#define __IFF_JOIN_H
+
+/**
+ * Joins an arbitrary number of IFF input files in a single concatenation chunk.
+ *
+ * @param inputFilenames An array of input IFF file names
+ * @param inputFilenamesLength Contains the length of the inputFilenames array
+ * @param outputFilename Specifies the name of the output file containing the resulting concatenation chunk. NULL can be used to write the result to the standard output.
+ * @return TRUE if the resulting concatenation has been successfully written, else FALSE
+ */
+int IFF_join(char **inputFilenames, const unsigned int inputFilenamesLength, const char *outputFilename);
+
+#endif

+ 154 - 0
ilbm.mod/libiff/src/iffjoin/main.c

@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_GETOPT_H == 1
+#include <getopt.h>
+#elif _MSC_VER
+#include <string.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "join.h"
+
+static void printUsage(const char *command)
+{
+    printf("Usage: %s [OPTION] file1.IFF file2.IFF ...\n\n", command);
+
+    puts(
+    "The command `iffjoin' joins an aribitrary number of IFF files into a single\n"
+    "concatenation IFF file. The result is written to the standard output, or\n"
+    "optionally to a given destination file.\n\n"
+
+    "Options:\n"
+#if _MSC_VER
+    "  /o FILE    Specify an output file name\n"
+    "  /?         Shows the usage of this command to the user\n"
+    "  /v         Shows the version of this command to the user"
+#else
+    "  -o, --output-file=FILE    Specify an output file name\n"
+    "  -h, --help                Shows the usage of this command to the user\n"
+    "  -v, --version             Shows the version of this command to the user"
+#endif
+    );
+}
+
+static void printVersion(const char *command)
+{
+    printf(
+    "%s (" PACKAGE_NAME ") " PACKAGE_VERSION "\n\n"
+    "Copyright (C) 2012-2015 Sander van der Burg\n"
+    , command);
+}
+
+int main(int argc, char *argv[])
+{
+    char *outputFilename = NULL;
+
+#if _MSC_VER
+    unsigned int optind = 1;
+    unsigned int i;
+
+    for(i = 1; i < argc; i++)
+    {
+        if (strcmp(argv[i], "/o") == 0)
+        {
+            outputFilename = argv[i];
+            optind++;
+        }
+        else if (strcmp(argv[i], "/?") == 0)
+        {
+            printUsage(argv[0]);
+            return 0;
+        }
+        else if (strcmp(argv[i], "/v") == 0)
+        {
+            printVersion(argv[0]);
+            return 0;
+        }
+    }
+#else
+    int c;
+#if HAVE_GETOPT_H == 1
+    int option_index = 0;
+    struct option long_options[] =
+    {
+        {"output-file", required_argument, 0, 'o'},
+        {"help", no_argument, 0, 'h'},
+        {"version", no_argument, 0, 'v'},
+        {0, 0, 0, 0}
+    };
+#endif
+    
+    /* Parse command-line options */
+#if HAVE_GETOPT_H == 1
+    while((c = getopt_long(argc, argv, "o:hv", long_options, &option_index)) != -1)
+#else
+    while((c = getopt(argc, argv, "o:hv")) != -1)
+#endif
+    {
+        switch(c)
+        {
+            case 'o':
+                outputFilename = optarg;
+                break;
+            case 'h':
+                printUsage(argv[0]);
+                return 0;
+            case '?':
+                printUsage(argv[0]);
+                return 1;
+            case 'v':
+                printVersion(argv[0]);
+                return 0;
+        }
+    }
+#endif
+    /* Validate non options */
+    
+    if(optind >= argc)
+    {
+        fprintf(stderr, "ERROR: No IFF input files given!\n");
+        return 1;
+    }
+    else
+    {
+        unsigned int inputFilenamesLength = argc - optind;
+        char **inputFilenames = (char**)malloc(inputFilenamesLength * sizeof(char*));
+        unsigned int i;
+        int status;
+        
+        /* Create an array of input file names */
+        for(i = 0; i < inputFilenamesLength; i++)
+            inputFilenames[i] = argv[optind + i];
+        
+        /* Join the IFF files */
+        status = IFF_join(inputFilenames, inputFilenamesLength, outputFilename);
+        
+        /* Cleanup */
+        free(inputFilenames);
+        
+        /* Return whether the join has succeeded or not */
+        return status;
+    }
+}

+ 14 - 0
ilbm.mod/libiff/src/iffpp/Makefile.am

@@ -0,0 +1,14 @@
+iffpp.1: main.c
+	$(HELP2MAN) --output=$@ --no-info --name 'IFF pretty printer' --libtool ./iffpp
+
+AM_CPPFLAGS = -DHAVE_GETOPT_H=$(HAVE_GETOPT_H)
+
+bin_PROGRAMS = iffpp
+noinst_HEADERS = pp.h
+man1_MANS = iffpp.1
+
+iffpp_SOURCES = main.c pp.c
+iffpp_LDADD = ../libiff/libiff.la
+iffpp_CFLAGS = -I../libiff
+
+EXTRA_DIST = iffpp.1

+ 86 - 0
ilbm.mod/libiff/src/iffpp/iffpp.vcxproj

@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{240D052E-85DD-4713-B2EA-B56F06D89883}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;PACKAGE_NAME="libiff";PACKAGE_VERSION="0.1";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>$(SolutionDir)\libiff;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>libiff.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="main.c" />
+    <ClCompile Include="pp.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="pp.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 30 - 0
ilbm.mod/libiff/src/iffpp/iffpp.vcxproj.filters

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="main.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="pp.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="pp.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 138 - 0
ilbm.mod/libiff/src/iffpp/main.c

@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_GETOPT_H == 1
+#include <getopt.h>
+#elif _MSC_VER
+#include <string.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "pp.h"
+
+static void printUsage(const char *command)
+{
+    printf("Usage: %s [OPTION] [file.IFF]\n\n", command);
+
+    puts(
+    "The command `iffpp' displays a textual representation of a given IFF file, which\n"
+    "can be used for manual inspection of its contents. If no IFF file is specified,\n"
+    "it reads an IFF file from the standard input.\n\n"
+
+    "Options:\n"
+#if _MSC_VER
+    "  /c    Do not check the IFF file for validity\n"
+    "  /?    Shows the usage of this command to the user\n"
+    "  /v    Shows the version of this command to the user"
+#else
+    "  -c, --disable-check    Do not check the IFF file for validity\n"
+    "  -h, --help             Shows the usage of this command to the user\n"
+    "  -v, --version          Shows the version of this command to the user"
+#endif
+    );
+}
+
+static void printVersion(const char *command)
+{
+    printf(
+    "%s (" PACKAGE_NAME ") " PACKAGE_VERSION "\n\n"
+    "Copyright (C) 2012-2015 Sander van der Burg\n"
+    , command);
+}
+
+int main(int argc, char *argv[])
+{
+    int options = 0;
+    char *filename;
+
+#if _MSC_VER
+    unsigned int optind = 1;
+    unsigned int i;
+
+    for(i = 1; i < argc; i++)
+    {
+        if (strcmp(argv[i], "/c") == 0)
+        {
+            options |= IFFPP_DISABLE_CHECK;
+            optind++;
+        }
+        else if (strcmp(argv[i], "/?") == 0)
+        {
+            printUsage(argv[0]);
+            return 0;
+        }
+        else if (strcmp(argv[i], "/v") == 0)
+        {
+            printVersion(argv[0]);
+            return 0;
+        }
+    }
+#else
+    int c;
+#if HAVE_GETOPT_H == 1
+    int option_index = 0;
+    struct option long_options[] =
+    {
+        {"disable-check", no_argument, 0, 'c'},
+        {"help", no_argument, 0, 'h'},
+        {"version", no_argument, 0, 'v'},
+        {0, 0, 0, 0}
+    };
+#endif
+
+    /* Parse command-line options */
+    
+#if HAVE_GETOPT_H == 1
+    while((c = getopt_long(argc, argv, "chv", long_options, &option_index)) != -1)
+#else
+    while((c = getopt(argc, argv, "chv")) != -1)
+#endif
+    {
+        switch(c)
+        {
+            case 'c':
+                options |= IFFPP_DISABLE_CHECK;
+                break;
+            case 'h':
+                printUsage(argv[0]);
+                return 0;
+            case '?':
+                printUsage(argv[0]);
+                return 1;
+            case 'v':
+                printVersion(argv[0]);
+                return 0;
+        }
+    }
+
+#endif
+    /* Validate non options */
+    
+    if(optind >= argc)
+        filename = NULL;
+    else
+        filename = argv[optind];
+
+    /* Pretty print the IFF file */
+    return IFF_prettyPrint(filename, options);
+}

+ 60 - 0
ilbm.mod/libiff/src/iffpp/pp.c

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "pp.h"
+#include "iff.h"
+
+int IFF_prettyPrint(const char *filename, const int options)
+{
+    IFF_Chunk *chunk;
+    
+    /* Parse the chunk */
+    if(filename == NULL)
+	chunk = IFF_readFd(stdin, NULL, 0);
+    else
+	chunk = IFF_read(filename, NULL, 0);
+    
+    if(chunk == NULL)
+    {
+	fprintf(stderr, "Cannot open IFF file!\n");
+	return 1;
+    }
+    else
+    {
+	int status;
+	
+	/* Check the file */
+	if((options & IFFPP_DISABLE_CHECK) || IFF_check(chunk, NULL, 0))
+	{
+	    /* Print the file */
+	    IFF_print(chunk, 0, NULL, 0);
+	    
+	    status = 0;
+	}
+	else
+	    status = 1;
+	
+	/* Free the chunk structure */
+	IFF_free(chunk, NULL, 0);
+	    
+	return status;
+    }
+}

+ 36 - 0
ilbm.mod/libiff/src/iffpp/pp.h

@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_PP_H
+#define __IFF_PP_H
+
+#define IFFPP_DISABLE_CHECK 0x01
+
+/**
+ * Displays a textual representation of the given IFF file.
+ *
+ * @param filename Path to the IFF file, or NULL to read from the standard input
+ * @param options An integer in which their bits represent a number of pretty print options
+ * @return TRUE if the file has been successfully printed, else FALSE
+ */
+int IFF_prettyPrint(const char *filename, const int options);
+
+#endif

+ 11 - 0
ilbm.mod/libiff/src/libiff.pc.in

@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libiff
+Version: @VERSION@
+Description: EA-85 IFF parser library
+Requires:
+Libs: -L${libdir} -liff
+Cflags: -I${includedir}

+ 40 - 0
ilbm.mod/libiff/src/libiff.sln

@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.21005.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libiff", "libiff\libiff.vcxproj", "{5857969C-CEB8-4BF3-BACB-81D7CE0FC654}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iffpp", "iffpp\iffpp.vcxproj", "{240D052E-85DD-4713-B2EA-B56F06D89883}"
+	ProjectSection(ProjectDependencies) = postProject
+		{5857969C-CEB8-4BF3-BACB-81D7CE0FC654} = {5857969C-CEB8-4BF3-BACB-81D7CE0FC654}
+	EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iffjoin", "iffjoin\iffjoin.vcxproj", "{A1D51E9B-7E52-4E13-8735-9A1E548BAAB1}"
+	ProjectSection(ProjectDependencies) = postProject
+		{5857969C-CEB8-4BF3-BACB-81D7CE0FC654} = {5857969C-CEB8-4BF3-BACB-81D7CE0FC654}
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{5857969C-CEB8-4BF3-BACB-81D7CE0FC654}.Debug|Win32.ActiveCfg = Debug|Win32
+		{5857969C-CEB8-4BF3-BACB-81D7CE0FC654}.Debug|Win32.Build.0 = Debug|Win32
+		{5857969C-CEB8-4BF3-BACB-81D7CE0FC654}.Release|Win32.ActiveCfg = Release|Win32
+		{5857969C-CEB8-4BF3-BACB-81D7CE0FC654}.Release|Win32.Build.0 = Release|Win32
+		{240D052E-85DD-4713-B2EA-B56F06D89883}.Debug|Win32.ActiveCfg = Debug|Win32
+		{240D052E-85DD-4713-B2EA-B56F06D89883}.Debug|Win32.Build.0 = Debug|Win32
+		{240D052E-85DD-4713-B2EA-B56F06D89883}.Release|Win32.ActiveCfg = Release|Win32
+		{240D052E-85DD-4713-B2EA-B56F06D89883}.Release|Win32.Build.0 = Release|Win32
+		{A1D51E9B-7E52-4E13-8735-9A1E548BAAB1}.Debug|Win32.ActiveCfg = Debug|Win32
+		{A1D51E9B-7E52-4E13-8735-9A1E548BAAB1}.Debug|Win32.Build.0 = Debug|Win32
+		{A1D51E9B-7E52-4E13-8735-9A1E548BAAB1}.Release|Win32.ActiveCfg = Release|Win32
+		{A1D51E9B-7E52-4E13-8735-9A1E548BAAB1}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 3 - 0
ilbm.mod/libiff/src/libiff/Makefile.am

@@ -0,0 +1,3 @@
+lib_LTLIBRARIES = libiff.la
+pkginclude_HEADERS = io.h id.h extension.h chunk.h group.h cat.h form.h list.h prop.h rawchunk.h util.h error.h iff.h ifftypes.h
+libiff_la_SOURCES = io.c id.c extension.c chunk.c group.c cat.c form.c list.c prop.c rawchunk.c util.c error.c iff.c

+ 134 - 0
ilbm.mod/libiff/src/libiff/cat.c

@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "cat.h"
+#include "id.h"
+#include "form.h"
+#include "list.h"
+#include "error.h"
+
+#define CAT_CHUNKID "CAT "
+#define CAT_GROUPTYPENAME "contentsType"
+
+IFF_CAT *IFF_createCAT(const char *contentsType)
+{
+    return (IFF_CAT*)IFF_createGroup(CAT_CHUNKID, contentsType);
+}
+
+void IFF_addToCAT(IFF_CAT *cat, IFF_Chunk *chunk)
+{
+    IFF_addToGroup((IFF_Group*)cat, chunk);
+}
+
+IFF_CAT *IFF_readCAT(io_context *context, const IFF_Long chunkSize, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return (IFF_CAT*)IFF_readGroup(context, CAT_CHUNKID, chunkSize, CAT_GROUPTYPENAME, FALSE, extension, extensionLength);
+}
+
+int IFF_writeCAT(FILE *file, const IFF_CAT *cat, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_writeGroup(file, (IFF_Group*)cat, NULL, CAT_GROUPTYPENAME, extension, extensionLength);
+}
+
+int IFF_checkCATSubChunk(const IFF_Group *group, const IFF_Chunk *subChunk)
+{
+    IFF_CAT *cat = (IFF_CAT*)group;
+    
+    /* A concatenation chunk may only contain other group chunks (except a PROP) */
+    
+    if(IFF_compareId(subChunk->chunkId, "FORM") != 0 &&
+       IFF_compareId(subChunk->chunkId, "LIST") != 0 &&
+       IFF_compareId(subChunk->chunkId, "CAT ") != 0)
+    {
+        IFF_error("ERROR: Element with chunk Id: '");
+        IFF_errorId(subChunk->chunkId);
+        IFF_error("' not allowed in CAT chunk!\n");
+        return FALSE;
+    }
+
+    if(IFF_compareId(cat->contentsType, "JJJJ") != 0)
+    {
+        /* Check whether form type or contents type matches the contents type of the CAT */
+	
+        if(IFF_compareId(subChunk->chunkId, "FORM") == 0)
+        {
+    	    IFF_Form *form = (IFF_Form*)subChunk;
+
+    	    if(IFF_compareId(form->formType, cat->contentsType) != 0)
+	    {
+	        IFF_error("Sub form does not match contentsType of the CAT!\n");
+	        return FALSE;
+	    }
+	}
+	else if(IFF_compareId(subChunk->chunkId, "LIST") == 0)
+	{
+	    IFF_List *list = (IFF_List*)subChunk;
+		
+	    if(IFF_compareId(list->contentsType, cat->contentsType) != 0)
+	    {
+	        IFF_error("Sub list does not match contentsType of the CAT!\n");
+	        return FALSE;
+	    }
+	}
+	else if(IFF_compareId(subChunk->chunkId, "CAT ") == 0)
+	{
+	    IFF_CAT *subCat = (IFF_CAT*)subChunk;
+		
+	    if(IFF_compareId(subCat->contentsType, cat->contentsType) != 0)
+	    {
+	        IFF_error("Sub cat does not match contentsType of the CAT!\n");
+	        return FALSE;
+	    }
+	}
+    }
+
+    return TRUE;
+}
+
+int IFF_checkCAT(const IFF_CAT *cat, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_checkGroup((IFF_Group*)cat, &IFF_checkId, &IFF_checkCATSubChunk, NULL, extension, extensionLength);
+}
+
+void IFF_freeCAT(IFF_CAT *cat, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_freeGroup((IFF_Group*)cat, NULL, extension, extensionLength);
+}
+
+void IFF_printCAT(const IFF_CAT *cat, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_printGroup((const IFF_Group*)cat, indentLevel, NULL, CAT_GROUPTYPENAME, extension, extensionLength);
+}
+
+int IFF_compareCAT(const IFF_CAT *cat1, const IFF_CAT *cat2, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_compareGroup((const IFF_Group*)cat1, (const IFF_Group*)cat2, NULL, extension, extensionLength);
+}
+
+IFF_Form **IFF_searchFormsInCAT(IFF_CAT *cat, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength)
+{
+    return IFF_searchFormsInGroup((IFF_Group*)cat, formTypes, formTypesLength, formsLength);
+}
+
+void IFF_updateCATChunkSizes(IFF_CAT *cat)
+{
+    IFF_updateGroupChunkSizes((IFF_Group*)cat);
+}

+ 176 - 0
ilbm.mod/libiff/src/libiff/cat.h

@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_CAT_H
+#define __IFF_CAT_H
+
+typedef struct IFF_CAT IFF_CAT;
+
+#include <stdio.h>
+#include "ifftypes.h"
+#include "chunk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief A special group chunk, which contains one or more FORM, LIST or CAT chunks.
+ */
+struct IFF_CAT
+{
+    /** Pointer to the parent group chunk, in which this chunk is located. The parent points to NULL if there is no parent. */
+    IFF_Group *parent;
+
+    /** Contains a 4 character ID of this chunk, which equals to 'CAT ' */
+    IFF_ID chunkId;
+    
+    /** Contains the size of the chunk data in bytes */
+    IFF_Long chunkSize;
+    
+    /**
+     * Contains a type ID which hints about the contents of this concatenation.
+     * 'JJJJ' is used if this concatenation stores forms of multiple form types.
+     * If only one form type is used in this concatenation, this contents type
+     * should be equal to that form type.
+     */
+    IFF_ID contentsType;
+    
+    /** Contains the number of sub chunks stored in this concatenation chunk */
+    unsigned int chunkLength;
+    
+    /** An array of chunk pointers referring to the sub chunks */
+    IFF_Chunk **chunk;
+};
+
+/**
+ * Creates a new concatentation chunk instance with the given contents type.
+ * The resulting chunk must be freed by using IFF_free().
+ *
+ * @param contentsType Contents type hinting what the contents of the CAT is.
+ * @return CAT chunk or NULL, if the memory for the struct can't be allocated
+ */
+IFF_CAT *IFF_createCAT(const char *contentsType);
+
+/**
+ * Adds a chunk to the body of the given CAT. This function also increments the
+ * chunk size and chunk length counter.
+ *
+ * @param cat An instance of a CAT struct
+ * @param chunk A FORM, CAT or LIST chunk
+ */
+void IFF_addToCAT(IFF_CAT *cat, IFF_Chunk *chunk);
+
+/**
+ * Reads a concatenation chunk and its sub chunks from a file. The resulting chunk must be
+ * freed by using IFF_free().
+ *
+ * @param file File descriptor of the file
+ * @param chunkSize Size of the chunk data
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return The concation struct derived from the file, or NULL if an error has occured
+ */
+IFF_CAT *IFF_readCAT(io_context *context, const IFF_Long chunkSize, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes a concatenation chunk and its sub chunks to a file.
+ *
+ * @param file File descriptor of the file
+ * @param cat An instance of a concatenation chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the CAT has been successfully written, else FALSE
+ */
+int IFF_writeCAT(FILE *file, const IFF_CAT *cat, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks a sub chunk in a CAT for its validity.
+ *
+ * @param group An instance of a concatenation chunk
+ * @param subChunk A sub chunk member of this concatenation chunk
+ * @return TRUE if the sub chunk is valid, else FALSE
+ */
+int IFF_checkCATSubChunk(const IFF_Group *group, const IFF_Chunk *subChunk);
+
+/**
+ * Checks whether the concatenation chunk and its sub chunks conform to the IFF specification.
+ *
+ * @param cat An instance of a concatenation chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the CAT is valid, else FALSE.
+ */
+int IFF_checkCAT(const IFF_CAT *cat, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Recursively frees the memory of the sub chunks of the given concatenation chunk.
+ *
+ * @param cat An instance of a concatenation chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_freeCAT(IFF_CAT *cat, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Displays a textual representation of the concatenation chunk and its sub chunks on the standard output.
+ *
+ * @param cat An instance of a concatenation chunk
+ * @param indentLevel Indent level of the textual representation
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_printCAT(const IFF_CAT *cat, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the given concatenations' contents is equal to each other.
+ *
+ * @param cat1 Concatenation to compare
+ * @param cat2 Concatenation to compare
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the given concatenations are equal, else FALSE
+ */
+int IFF_compareCAT(const IFF_CAT *cat1, const IFF_CAT *cat2, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Returns an array of form structs of the given formType, which are recursively retrieved from the given CAT.
+ *
+ * @param cat An instance of a concatenation chunk
+ * @param formTypes An array of 4 character form type IDs
+ * @param formTypesLength Length of the form types array
+ * @param formsLength Returns the length of the resulting array
+ * @return An array of form structs
+ */
+IFF_Form **IFF_searchFormsInCAT(IFF_CAT *cat, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength);
+
+/**
+ * Recalculates the chunk size of the given concatentation chunk.
+ *
+ * @param cat An instance of a concatenation chunk
+ */
+void IFF_updateCATChunkSizes(IFF_CAT *cat);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 282 - 0
ilbm.mod/libiff/src/libiff/chunk.c

@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "chunk.h"
+#include <string.h>
+#include <stdlib.h>
+#include "extension.h"
+#include "io.h"
+#include "id.h"
+#include "util.h"
+#include "form.h"
+#include "cat.h"
+#include "list.h"
+#include "prop.h"
+#include "rawchunk.h"
+#include "util.h"
+#include "error.h"
+
+IFF_Chunk *IFF_allocateChunk(const char *chunkId, const size_t chunkSize)
+{
+    IFF_Chunk *chunk = (IFF_Chunk*)malloc(chunkSize);
+    
+    chunk->parent = NULL;
+    IFF_createId(chunk->chunkId, chunkId);
+    chunk->chunkSize = 0;
+    
+    return chunk;
+}
+
+IFF_Chunk *IFF_readChunk(io_context *context, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_ID chunkId;
+    IFF_Long chunkSize;
+    
+    /* Read chunk id */
+    if(!IFF_readId(context, chunkId, "", chunkId))
+	return NULL;
+    
+    /* Read chunk size */
+    if(!IFF_readLong(context, &chunkSize, chunkId, "chunkSize"))
+	return NULL;
+
+    /* Read remaining bytes (procedure depends on chunk id type) */
+    
+    if(IFF_compareId(chunkId, "FORM") == 0)
+	return (IFF_Chunk*)IFF_readForm(context, chunkSize, extension, extensionLength);
+    else if(IFF_compareId(chunkId, "CAT ") == 0)
+	return (IFF_Chunk*)IFF_readCAT(context, chunkSize, extension, extensionLength);
+    else if(IFF_compareId(chunkId, "LIST") == 0)
+	return (IFF_Chunk*)IFF_readList(context, chunkSize, extension, extensionLength);
+    else if(IFF_compareId(chunkId, "PROP") == 0)
+	return (IFF_Chunk*)IFF_readProp(context, chunkSize, extension, extensionLength);
+    else
+    {
+	const IFF_FormExtension *formExtension = IFF_findFormExtension(formType, chunkId, extension, extensionLength);
+	
+	if(formExtension == NULL)
+	    return (IFF_Chunk*)IFF_readRawChunk(context, chunkId, chunkSize);
+	else
+	    return formExtension->readChunk(context, chunkSize);
+    }
+}
+
+int IFF_writeChunk(FILE *file, const IFF_Chunk *chunk, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    if(!IFF_writeId(file, chunk->chunkId, chunk->chunkId, "chunkId"))
+	return FALSE;
+    
+    if(!IFF_writeLong(file, chunk->chunkSize, chunk->chunkId, "chunkSize"))
+	return FALSE;
+    
+    if(IFF_compareId(chunk->chunkId, "FORM") == 0)
+    {
+	if(!IFF_writeForm(file, (IFF_Form*)chunk, extension, extensionLength))
+	    return FALSE;
+    }
+    else if(IFF_compareId(chunk->chunkId, "CAT ") == 0)
+    {
+	if(!IFF_writeCAT(file, (IFF_CAT*)chunk, extension, extensionLength))
+	    return FALSE;
+    }
+    else if(IFF_compareId(chunk->chunkId, "LIST") == 0)
+    {
+	if(!IFF_writeList(file, (IFF_List*)chunk, extension, extensionLength))
+	    return FALSE;
+    }
+    else if(IFF_compareId(chunk->chunkId, "PROP") == 0)
+    {
+	if(!IFF_writeProp(file, (IFF_Prop*)chunk, extension, extensionLength))
+	    return FALSE;
+    }
+    else
+    {
+	const IFF_FormExtension *formExtension = IFF_findFormExtension(formType, chunk->chunkId, extension, extensionLength);
+	    
+	if(formExtension == NULL)
+	    return IFF_writeRawChunk(file, (IFF_RawChunk*)chunk);
+	else
+	    return formExtension->writeChunk(file, chunk);
+    }
+    
+    return TRUE;
+}
+
+int IFF_checkChunk(const IFF_Chunk *chunk, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    if(!IFF_checkId(chunk->chunkId))
+	return FALSE;
+    else
+    {
+	if(IFF_compareId(chunk->chunkId, "FORM") == 0)
+	    return IFF_checkForm((const IFF_Form*)chunk, extension, extensionLength);
+	else if(IFF_compareId(chunk->chunkId, "CAT ") == 0)
+	    return IFF_checkCAT((const IFF_CAT*)chunk, extension, extensionLength);
+	else if(IFF_compareId(chunk->chunkId, "LIST") == 0)
+	    return IFF_checkList((const IFF_List*)chunk, extension, extensionLength);
+	else if(IFF_compareId(chunk->chunkId, "PROP") == 0)
+	    return IFF_checkProp((const IFF_Prop*)chunk, extension, extensionLength);
+	else
+	{
+	    const IFF_FormExtension *formExtension = IFF_findFormExtension(formType, chunk->chunkId, extension, extensionLength);
+		
+	    if(formExtension == NULL)
+		return TRUE;
+	    else
+	        return formExtension->checkChunk(chunk);
+	}
+    }
+}
+
+void IFF_freeChunk(IFF_Chunk *chunk, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    /* Free nested sub chunks */
+    if(IFF_compareId(chunk->chunkId, "FORM") == 0)
+	IFF_freeForm((IFF_Form*)chunk, extension, extensionLength);
+    else if(IFF_compareId(chunk->chunkId, "CAT ") == 0)
+	IFF_freeCAT((IFF_CAT*)chunk, extension, extensionLength);
+    else if(IFF_compareId(chunk->chunkId, "LIST") == 0)
+	IFF_freeList((IFF_List*)chunk, extension, extensionLength);
+    else if(IFF_compareId(chunk->chunkId, "PROP") == 0)
+	IFF_freeProp((IFF_Prop*)chunk, extension, extensionLength);
+    else
+    {
+	const IFF_FormExtension *formExtension = IFF_findFormExtension(formType, chunk->chunkId, extension, extensionLength);
+	    
+	if(formExtension == NULL)
+	    IFF_freeRawChunk((IFF_RawChunk*)chunk);
+	else
+	    formExtension->freeChunk(chunk);
+    }
+    
+    /* Free the chunk itself */
+    free(chunk);
+}
+
+void IFF_printChunk(const IFF_Chunk *chunk, const unsigned int indentLevel, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_printIndent(stdout, indentLevel, "'");
+    IFF_printId(chunk->chunkId);
+    printf("' = {\n");
+    
+    IFF_printIndent(stdout, indentLevel + 1, "chunkSize = %d;\n", chunk->chunkSize);
+    
+    if(IFF_compareId(chunk->chunkId, "FORM") == 0)
+	IFF_printForm((const IFF_Form*)chunk, indentLevel + 1, extension, extensionLength);
+    else if(IFF_compareId(chunk->chunkId, "CAT ") == 0)
+	IFF_printCAT((const IFF_CAT*)chunk, indentLevel + 1, extension, extensionLength);
+    else if(IFF_compareId(chunk->chunkId, "LIST") == 0)
+	IFF_printList((const IFF_List*)chunk, indentLevel + 1, extension, extensionLength);
+    else if(IFF_compareId(chunk->chunkId, "PROP") == 0)
+	IFF_printProp((const IFF_Prop*)chunk, indentLevel + 1, extension, extensionLength);
+    else
+    {
+	const IFF_FormExtension *formExtension = IFF_findFormExtension(formType, chunk->chunkId, extension, extensionLength);
+	
+	if(formExtension == NULL)
+	    IFF_printRawChunk((IFF_RawChunk*)chunk, indentLevel + 1);
+	else
+	    formExtension->printChunk(chunk, indentLevel + 1);
+    }
+    
+    IFF_printIndent(stdout, indentLevel, "}\n\n");
+}
+
+int IFF_compareChunk(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    if(IFF_compareId(chunk1->chunkId, chunk2->chunkId) == 0)
+    {
+	if(chunk1->chunkSize == chunk2->chunkSize)
+	{
+	    if(IFF_compareId(chunk1->chunkId, "FORM") == 0)
+		return IFF_compareForm((const IFF_Form*)chunk1, (const IFF_Form*)chunk2, extension, extensionLength);
+	    else if(IFF_compareId(chunk1->chunkId, "CAT ") == 0)
+		return IFF_compareCAT((const IFF_CAT*)chunk1, (const IFF_CAT*)chunk2, extension, extensionLength);
+	    else if(IFF_compareId(chunk1->chunkId, "LIST") == 0)
+		return IFF_compareList((const IFF_List*)chunk1, (const IFF_List*)chunk2, extension, extensionLength);
+	    else if(IFF_compareId(chunk1->chunkId, "PROP") == 0)
+		return IFF_compareProp((const IFF_Prop*)chunk1, (const IFF_Prop*)chunk2, extension, extensionLength);
+	    else
+	    {
+		const IFF_FormExtension *formExtension = IFF_findFormExtension(formType, chunk1->chunkId, extension, extensionLength);
+		
+		if(formExtension == NULL)
+		    return IFF_compareRawChunk((const IFF_RawChunk*)chunk1, (const IFF_RawChunk*)chunk2);
+		else
+		    return formExtension->compareChunk(chunk1, chunk2);
+	    }
+	}
+	else
+	    return FALSE;
+    }
+    else
+	return FALSE;
+}
+
+IFF_Form **IFF_searchFormsFromArray(IFF_Chunk *chunk, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength)
+{
+    if(IFF_compareId(chunk->chunkId, "FORM") == 0)
+	return IFF_searchFormsInForm((IFF_Form*)chunk, formTypes, formTypesLength, formsLength);
+    else if(IFF_compareId(chunk->chunkId, "CAT ") == 0)
+	return IFF_searchFormsInCAT((IFF_CAT*)chunk, formTypes, formTypesLength, formsLength);
+    else if(IFF_compareId(chunk->chunkId, "LIST") == 0)
+	return IFF_searchFormsInList((IFF_List*)chunk, formTypes, formTypesLength, formsLength);
+    else
+    {
+	*formsLength = 0;
+	return NULL;
+    }
+}
+
+IFF_Form **IFF_searchForms(IFF_Chunk *chunk, const char *formType, unsigned int *formsLength)
+{
+    const char *formTypes[1];
+    formTypes[0] = formType;
+    return IFF_searchFormsFromArray(chunk, formTypes, 1, formsLength);
+}
+
+IFF_Long IFF_incrementChunkSize(const IFF_Long chunkSize, const IFF_Chunk *chunk)
+{
+    IFF_Long returnValue = chunkSize + IFF_ID_SIZE + sizeof(IFF_Long) + chunk->chunkSize;
+    
+    /* If the size of the nested chunk size is odd, we have to count the padding byte as well */
+    if(chunk->chunkSize % 2 != 0)
+        returnValue++;
+        
+    return returnValue;
+}
+
+void IFF_updateChunkSizes(IFF_Chunk *chunk)
+{
+    /* Check whether the given chunk is a group chunk and update the sizes */
+    if(IFF_compareId(chunk->chunkId, "FORM") == 0)
+	IFF_updateFormChunkSizes((IFF_Form*)chunk);
+    else if(IFF_compareId(chunk->chunkId, "PROP") == 0)
+	IFF_updatePropChunkSizes((IFF_Prop*)chunk);
+    else if(IFF_compareId(chunk->chunkId, "CAT ") == 0)
+	IFF_updateCATChunkSizes((IFF_CAT*)chunk);
+    else if(IFF_compareId(chunk->chunkId, "LIST") == 0)
+	IFF_updateListChunkSizes((IFF_List*)chunk);
+    
+    /* If the given type has a parent, recursively update these as well */
+    if(chunk->parent != NULL)
+	IFF_updateChunkSizes((IFF_Chunk*)chunk->parent);
+}

+ 172 - 0
ilbm.mod/libiff/src/libiff/chunk.h

@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_CHUNK_H
+#define __IFF_CHUNK_H
+
+typedef struct IFF_Chunk IFF_Chunk;
+
+#include <stdio.h>
+#include "ifftypes.h"
+#include "extension.h"
+#include "group.h"
+#include "form.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief An abstract chunk containing the common properties of all chunk types
+ */
+struct IFF_Chunk
+{
+    /** Pointer to the parent group chunk, in which this chunk is located. The parent points to NULL if there is no parent. */
+    IFF_Group *parent;
+    
+    /** Contains a 4 character ID of this chunk */
+    IFF_ID chunkId;
+    
+    /** Contains the size of the chunk data in bytes */
+    IFF_Long chunkSize;
+};
+
+/**
+ * Allocates memory for a chunk with the given chunk ID and chunk size.
+ * The resulting chunk must be freed using IFF_free()
+ *
+ * @param chunkId A 4 character id
+ * @param chunkSize Size of the chunk in bytes
+ * @return A generic chunk with the given chunk Id and size, or NULL if the memory can't be allocated.
+ */
+IFF_Chunk *IFF_allocateChunk(const char *chunkId, const size_t chunkSize);
+
+/**
+ * Reads a chunk hierarchy from a given file descriptor. The resulting chunk must be freed using IFF_free()
+ *
+ * @param file File descriptor of the file
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return A chunk hierarchy derived from the IFF file, or NULL if an error occurs
+ */
+IFF_Chunk *IFF_readChunk(io_context *context, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes a chunk hierarchy to a given file descriptor.
+ *
+ * @param file File descriptor of the file
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the file has been successfully written, else FALSE
+ */
+int IFF_writeChunk(FILE *file, const IFF_Chunk *chunk, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether a chunk hierarchy conforms to the IFF specification.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the IFF file conforms to the IFF specification, else FALSE
+ */
+int IFF_checkChunk(const IFF_Chunk *chunk, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Frees an IFF chunk hierarchy from memory.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_freeChunk(IFF_Chunk *chunk, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Displays a textual representation of an IFF chunk hierarchy on the standard output.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param indentLevel Indent level of the textual representation
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_printChunk(const IFF_Chunk *chunk, const unsigned int indentLevel, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether two given chunk hierarchies are equal.
+ *
+ * @param chunk1 Chunk hierarchy to compare
+ * @param chunk2 Chunk hierarchy to compare
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the given chunk hierarchies are equal, else FALSE
+ */
+int IFF_compareChunk(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Recursively searches for all FORMs with the given form types in a chunk hierarchy.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param formTypes An array of 4 character form identifiers
+ * @param formTypesLength Length of the form types array
+ * @param formsLength An integer in which the length of the resulting array is stored
+ * @return An array of forms having the given form type
+ */
+IFF_Form **IFF_searchFormsFromArray(IFF_Chunk *chunk, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength);
+
+/**
+ * Recursively searches for all FORMs with the given form type in a chunk hierarchy.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param formType A 4 character form identifier
+ * @param formsLength An integer in which the length of the resulting array is stored
+ * @return An array of forms having the given form type
+ */
+
+IFF_Form **IFF_searchForms(IFF_Chunk *chunk, const char *formType, unsigned int *formsLength);
+
+/**
+ * Increments the given chunk size by the size of the given chunk.
+ * Additionally, it takes the padding byte into account if the chunk size is odd.
+ *
+ * @param chunkSize Chunk size of a group chunk
+ * @param chunk A sub chunk
+ * @return The incremented chunk size with an optional padding byte
+ */
+IFF_Long IFF_incrementChunkSize(const IFF_Long chunkSize, const IFF_Chunk *chunk);
+
+/**
+ * Recalculates the chunk size of the given chunk and recursively updates the chunk sizes of the parent group chunks.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ */
+void IFF_updateChunkSizes(IFF_Chunk *chunk);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 61 - 0
ilbm.mod/libiff/src/libiff/error.c

@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "error.h"
+#include <stdio.h>
+
+void IFF_errorCallbackStderr(const char *formatString, va_list ap)
+{
+    vfprintf(stderr, formatString, ap);
+}
+
+void (*IFF_errorCallback) (const char *formatString, va_list ap) = &IFF_errorCallbackStderr;
+
+void IFF_error(const char *formatString, ...)
+{
+    va_list ap;
+    
+    va_start(ap, formatString);
+    IFF_errorCallback(formatString, ap);
+    va_end(ap);
+}
+
+void IFF_errorId(const IFF_ID id)
+{
+    unsigned int i;
+    
+    for(i = 0; i < IFF_ID_SIZE; i++)
+	IFF_error("%c", id[i]);
+}
+
+void IFF_readError(const IFF_ID chunkId, const char *attributeName)
+{
+    IFF_error("Error reading '");
+    IFF_errorId(chunkId);
+    IFF_error("'.%s\n", attributeName);
+}
+
+void IFF_writeError(const IFF_ID chunkId, const char *attributeName)
+{
+    IFF_error("Error writing '");
+    IFF_errorId(chunkId);
+    IFF_error("'.%s\n", attributeName);
+}

+ 79 - 0
ilbm.mod/libiff/src/libiff/error.h

@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_ERROR_H
+#define __IFF_ERROR_H
+
+#include <stdarg.h>
+#include "id.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A function pointer specifying which error callback function should be used.
+ */
+extern void (*IFF_errorCallback) (const char *formatString, va_list ap);
+
+/**
+ * An error callback function printing errors to the standard error.
+ *
+ * @param formatString A format specifier for fprintf()
+ * @param ap A list of command-line parameters
+ */
+void IFF_errorCallbackStderr(const char *formatString, va_list ap);
+
+/**
+ * The error callback function used by the IFF library and derivatives.
+ *
+ * @param formatString A format specifier for fprintf()
+ */
+void IFF_error(const char *formatString, ...);
+
+/**
+ * Prints a 4 character IFF id on the standard error
+ *
+ * @param id A 4 character IFF id
+ */
+void IFF_errorId(const IFF_ID id);
+
+/**
+ * Prints a standard read error message.
+ *
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ */
+void IFF_readError(const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Prints a standard write error message.
+ *
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ */
+void IFF_writeError(const IFF_ID chunkId, const char *attributeName);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 88 - 0
ilbm.mod/libiff/src/libiff/extension.c

@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "extension.h"
+#include <stdlib.h>
+#include "id.h"
+
+static int compareExtension(const void *a, const void *b)
+{
+    const IFF_Extension *l = (IFF_Extension*)a;
+    const IFF_Extension *r = (IFF_Extension*)b;
+    
+    return IFF_compareId(l->formType, r->formType);
+}
+
+const static IFF_FormExtension *getFormExtensions(const char *formType, const IFF_Extension *extension, const unsigned int extensionLength, unsigned int *formExtensionsLength)
+{
+    IFF_Extension key;
+    IFF_Extension *result;
+    
+    key.formType = formType;
+    
+    result = bsearch(&key, extension, extensionLength, sizeof(IFF_Extension), &compareExtension);
+
+    if(result == NULL)
+    {
+	*formExtensionsLength = 0;
+	return NULL;
+    }
+    else
+    {
+	*formExtensionsLength = result->formExtensionsLength;
+	return result->formExtensions;
+    }
+}
+
+static int compareFormExtension(const void *a, const void *b)
+{
+    const IFF_FormExtension *l = (IFF_FormExtension*)a;
+    const IFF_FormExtension *r = (IFF_FormExtension*)b;
+    
+    return IFF_compareId(l->chunkId, r->chunkId);
+}
+
+const static IFF_FormExtension *getFormExtension(const char *chunkId, const IFF_FormExtension *formExtension, const unsigned int formExtensionLength)
+{
+    IFF_FormExtension key;
+    key.chunkId = chunkId;
+    
+    return bsearch(&key, formExtension, formExtensionLength, sizeof(IFF_FormExtension), &compareFormExtension);
+}
+
+const IFF_FormExtension *IFF_findFormExtension(const char *formType, const char *chunkId, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    if(formType == NULL)
+	return NULL;
+    else
+    {
+	unsigned int formExtensionsLength;
+	
+	/* Search the given form extensions array */
+	const IFF_FormExtension *formExtensions = getFormExtensions(formType, extension, extensionLength, &formExtensionsLength);
+	
+	/* Search for the extension that handles the a chunk with the given chunk id */
+	const IFF_FormExtension *formExtension = getFormExtension(chunkId, formExtensions, formExtensionsLength);
+    
+	/* Return the form extension we have found */
+	return formExtension;
+    }
+}

+ 93 - 0
ilbm.mod/libiff/src/libiff/extension.h

@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_EXTENSION_H
+#define __IFF_EXTENSION_H
+
+typedef struct IFF_FormExtension IFF_FormExtension;
+typedef struct IFF_Extension IFF_Extension;
+
+#include <stdio.h>
+#include "ifftypes.h"
+#include "chunk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Defines how a particular application chunk within a FORM should be handled.
+ */
+struct IFF_FormExtension
+{
+    /** A 4 character chunk id */
+    const char *chunkId;
+    
+    /** Function resposible for reading the given chunk */
+    IFF_Chunk* (*readChunk) (io_context *context, const IFF_Long chunkSize);
+    
+    /** Function resposible for writing the given chunk */
+    int (*writeChunk) (FILE *file, const IFF_Chunk *chunk);
+    
+    /** Function resposible for checking the given chunk */
+    int (*checkChunk) (const IFF_Chunk *chunk);
+    
+    /** Function resposible for freeing the given chunk */
+    void (*freeChunk) (IFF_Chunk *chunk);
+    
+    /** Function responsible for printing the given chunk */
+    void (*printChunk) (const IFF_Chunk *chunk, const unsigned int indentLevel);
+    
+    /** Function responsible for comparing the given chunk */
+    int (*compareChunk) (const IFF_Chunk *chunk1, const IFF_Chunk *chunk2);
+};
+
+/**
+ * @brief Defines how application chunks in a FORM with a particular formType should be handled.
+ */
+struct IFF_Extension
+{
+    /** A 4 character form type id */
+    const char *formType;
+    
+    /** Specifies the number of application chunks in the form that should be handled by external functions */
+    unsigned int formExtensionsLength;
+    
+    /** An array specifying how application chunks within the form context should be handled */
+    IFF_FormExtension *formExtensions;
+};
+
+/**
+ * Searches for a form extension that can deal with a chunk in a given form with a form type and a given chunk id
+ *
+ * @param formType A 4 character form type id. If the formType is NULL, the function will always return NULL
+ * @param chunkId A 4 character chunk id
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return The form extension that handles the specified chunk or NULL if it does not exists
+ */
+const IFF_FormExtension *IFF_findFormExtension(const char *formType, const char *chunkId, const IFF_Extension *extension, const unsigned int extensionLength);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 291 - 0
ilbm.mod/libiff/src/libiff/form.c

@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "form.h"
+#include <string.h>
+#include <stdlib.h>
+#include "id.h"
+#include "util.h"
+#include "list.h"
+#include "error.h"
+
+#define FORM_CHUNKID "FORM"
+#define FORM_GROUPTYPENAME "formType"
+
+IFF_Form *IFF_createForm(const char *formType)
+{
+    return (IFF_Form*)IFF_createGroup(FORM_CHUNKID, formType);
+}
+
+void IFF_addToForm(IFF_Form *form, IFF_Chunk *chunk)
+{
+    IFF_addToGroup((IFF_Group*)form, chunk);
+}
+
+IFF_Form *IFF_readForm(FILE *file, const IFF_Long chunkSize, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return (IFF_Form*)IFF_readGroup(file, FORM_CHUNKID, chunkSize, FORM_GROUPTYPENAME, TRUE, extension, extensionLength);
+}
+
+int IFF_writeForm(FILE *file, const IFF_Form *form, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_writeGroup(file, (IFF_Group*)form, form->formType, FORM_GROUPTYPENAME, extension, extensionLength);
+}
+
+int IFF_checkFormType(const IFF_ID formType)
+{
+    unsigned int i;
+    
+    /* A form type must be a valid ID */
+    if(!IFF_checkId(formType))
+	return FALSE;
+
+    /* A form type is not allowed to have lowercase or puntuaction marks */
+    for(i = 0; i < IFF_ID_SIZE; i++)
+    {
+	if((formType[i] >= 0x61 && formType[i] <= 0x7a) || formType[i] == '.')
+	{
+	    IFF_error("No lowercase characters or punctuation marks allowed in a form type ID!\n");
+	    return FALSE;
+	}
+    }
+    
+    /* A form ID is not allowed to be equal to a group chunk ID */
+    
+    if(IFF_compareId(formType, "LIST") == 0 ||
+       IFF_compareId(formType, "FORM") == 0 ||
+       IFF_compareId(formType, "PROP") == 0 ||
+       IFF_compareId(formType, "CAT ") == 0 ||
+       IFF_compareId(formType, "JJJJ") == 0 ||
+       IFF_compareId(formType, "LIS1") == 0 ||
+       IFF_compareId(formType, "LIS2") == 0 ||
+       IFF_compareId(formType, "LIS3") == 0 ||
+       IFF_compareId(formType, "LIS4") == 0 ||
+       IFF_compareId(formType, "LIS5") == 0 ||
+       IFF_compareId(formType, "LIS6") == 0 ||
+       IFF_compareId(formType, "LIS7") == 0 ||
+       IFF_compareId(formType, "LIS8") == 0 ||
+       IFF_compareId(formType, "LIS9") == 0 ||
+       IFF_compareId(formType, "FOR1") == 0 ||
+       IFF_compareId(formType, "FOR1") == 0 ||
+       IFF_compareId(formType, "FOR2") == 0 ||
+       IFF_compareId(formType, "FOR3") == 0 ||
+       IFF_compareId(formType, "FOR4") == 0 ||
+       IFF_compareId(formType, "FOR5") == 0 ||
+       IFF_compareId(formType, "FOR6") == 0 ||
+       IFF_compareId(formType, "FOR7") == 0 ||
+       IFF_compareId(formType, "FOR8") == 0 ||
+       IFF_compareId(formType, "FOR9") == 0 ||
+       IFF_compareId(formType, "CAT1") == 0 ||
+       IFF_compareId(formType, "CAT2") == 0 ||
+       IFF_compareId(formType, "CAT3") == 0 ||
+       IFF_compareId(formType, "CAT4") == 0 ||
+       IFF_compareId(formType, "CAT5") == 0 ||
+       IFF_compareId(formType, "CAT6") == 0 ||
+       IFF_compareId(formType, "CAT7") == 0 ||
+       IFF_compareId(formType, "CAT8") == 0 ||
+       IFF_compareId(formType, "CAT9") == 0)
+    {
+	IFF_error("Form type: '");
+	IFF_errorId(formType);
+	IFF_error("' not allowed!\n");
+	
+	return FALSE;
+    }
+    
+    return TRUE;
+}
+
+static int subChunkCheck(const IFF_Group *group, const IFF_Chunk *subChunk)
+{
+    if(IFF_compareId(subChunk->chunkId, "PROP") == 0)
+    {
+        IFF_error("ERROR: Element with chunk Id: '");
+        IFF_errorId(subChunk->chunkId);
+        IFF_error("' not allowed in FORM chunk!\n");
+	
+        return FALSE;
+    }
+    else
+	return TRUE;
+}
+
+int IFF_checkForm(const IFF_Form *form, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_checkGroup((IFF_Group*)form, &IFF_checkFormType, &subChunkCheck, form->formType, extension, extensionLength);
+}
+
+void IFF_freeForm(IFF_Form *form, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_freeGroup((IFF_Group*)form, form->formType, extension, extensionLength);
+}
+
+void IFF_printForm(const IFF_Form *form, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_printGroup((const IFF_Group*)form, indentLevel, form->formType, FORM_GROUPTYPENAME, extension, extensionLength);
+}
+
+int IFF_compareForm(const IFF_Form *form1, const IFF_Form *form2, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_compareGroup((const IFF_Group*)form1, (const IFF_Group*)form2, form1->formType, extension, extensionLength);
+}
+
+IFF_Form **IFF_mergeFormArray(IFF_Form **target, unsigned int *targetLength, IFF_Form **source, const unsigned int sourceLength)
+{
+    unsigned int i;
+    unsigned int newLength = *targetLength + sourceLength;
+    
+    target = (IFF_Form**)realloc(target, newLength * sizeof(IFF_Form*));
+    
+    for(i = 0; i < sourceLength; i++)
+	target[i + *targetLength] = source[i];
+    
+    *targetLength = newLength;
+    
+    return target;
+}
+
+IFF_Form **IFF_searchFormsInForm(IFF_Form *form, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength)
+{
+    unsigned int i;
+
+    /* If the given form is what we look for, return it */
+    for(i = 0; i < formTypesLength; i++)
+    {
+        const char *formType = formTypes[i];
+
+        if(IFF_compareId(form->formType, formType) == 0)
+        {
+            IFF_Form **forms = (IFF_Form**)malloc(sizeof(IFF_Form*));
+            forms[0] = form;
+            *formsLength = 1;
+
+            return forms;
+        }
+    }
+
+    return IFF_searchFormsInGroup((IFF_Group*)form, formTypes, formTypesLength, formsLength); /* Search into the nested forms in this form */
+}
+
+void IFF_updateFormChunkSizes(IFF_Form *form)
+{
+    IFF_updateGroupChunkSizes((IFF_Group*)form);
+}
+
+/**
+ * Searches the list in which the given chunk is (indirectly) a member from.
+ *
+ * @param chunk An arbitrary chunk, which could be (indirectly) a member of a list
+ * @return List instance of which the given chunk is (indirectly) a member, or NULL if the chunk is not a member of a list
+ */
+static IFF_List *searchList(const IFF_Chunk *chunk)
+{
+    IFF_Group *parent = chunk->parent;
+    
+    if(parent == NULL)
+	return NULL;
+    else
+    {
+	if(IFF_compareId(parent->chunkId, "LIST") == 0)
+	    return (IFF_List*)parent;
+	else
+	    return searchList((IFF_Chunk*)parent);
+    }
+}
+
+/**
+ * Recursively searches for a shared list property with the given chunk ID.
+ *
+ * @param chunk An arbitrary chunk, which could be (indirectly) a member of a list
+ * @param formType A 4 character form id
+ * @param chunkId A 4 character chunk id
+ * @return The chunk with the given chunk id, or NULL if the chunk can't be found
+ */
+static IFF_Chunk *searchProperty(const IFF_Chunk *chunk, const char *formType, const char *chunkId)
+{
+    IFF_List *list = searchList(chunk);
+    
+    if(list == NULL)
+	return NULL; /* If the chunk is not (indirectly) in a list, we have no shared properties at all */
+    else
+    {
+	/* Try requesting the PROP chunk for the given form type */
+	IFF_Prop *prop = IFF_getPropFromList(list, formType);
+	
+	if(prop == NULL)
+	    return searchProperty((IFF_Chunk*)list, formType, chunkId); /* If we can't find a shared property chunk with the given form type, try searching for a list higher in the hierarchy */
+	else
+	{
+	    /* Try requesting the chunk from the shared property chunk */
+	    IFF_Chunk *chunk = IFF_getChunkFromProp(prop, chunkId);
+	    
+	    if(chunk == NULL)
+		return searchProperty((IFF_Chunk*)list, formType, chunkId); /* If the requested chunk is not in the PROP chunk, try searching for a list higher in the hierarchy */
+	    else
+		return chunk; /* We have found the requested shared property chunk */
+	}
+    }
+}
+
+IFF_Chunk *IFF_getDataChunkFromForm(const IFF_Form *form, const char *chunkId)
+{
+    unsigned int i;
+    
+    for(i = 0; i < form->chunkLength; i++)
+    {
+	if(IFF_compareId(form->chunk[i]->chunkId, chunkId) == 0)
+	    return form->chunk[i];
+    }
+    
+    return NULL;
+}
+
+IFF_Chunk *IFF_getChunkFromForm(const IFF_Form *form, const char *chunkId)
+{
+    /* Retrieve the chunk with the given id from the given form */
+    IFF_Chunk *chunk = IFF_getDataChunkFromForm(form, chunkId);
+    
+    /* If the chunk is not in the form, try to find it in a higher located PROP */
+    if(chunk == NULL)
+	return searchProperty((IFF_Chunk*)form, form->formType, chunkId);
+    else
+	return chunk;
+}
+
+IFF_Chunk **IFF_getChunksFromForm(const IFF_Form *form, const char *chunkId, unsigned int *chunksLength)
+{
+    IFF_Chunk **result = NULL;
+    unsigned int i;
+    
+    *chunksLength = 0;
+    
+    for(i = 0; i < form->chunkLength; i++)
+    {
+	if(IFF_compareId(form->chunk[i]->chunkId, chunkId) == 0)
+	{
+	    result = (IFF_Chunk**)realloc(result, (*chunksLength + 1) * sizeof(IFF_Chunk*));
+	    result[*chunksLength] = form->chunk[i];
+	    *chunksLength = *chunksLength + 1;
+	}
+    }
+    
+    return result;
+}

+ 215 - 0
ilbm.mod/libiff/src/libiff/form.h

@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_FORM_H
+#define __IFF_FORM_H
+
+typedef struct IFF_Form IFF_Form;
+
+#include <stdio.h>
+#include "ifftypes.h"
+#include "chunk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief A special group chunk, which contains an arbitrary number of group chunks and data chunks.
+ */
+struct IFF_Form
+{
+    /** Pointer to the parent group chunk, in which this chunk is located. The parent points to NULL if there is no parent. */
+    IFF_Group *parent;
+
+    /** Contains the ID of this chunk, which equals to 'FORM' */
+    IFF_ID chunkId;
+    
+    /** Contains the size of the chunk data in bytes */
+    IFF_Long chunkSize;
+    
+    /**
+     * Contains a form type, which is used for most application file formats as an
+     * application file format identifier
+     */
+    IFF_ID formType;
+    
+    /** Contains the number of sub chunks stored in this form chunk */
+    unsigned int chunkLength;
+    
+    /** An array of chunk pointers referring to the sub chunks */
+    IFF_Chunk **chunk;
+};
+
+/**
+ * Creates a new form chunk instance with the given form type.
+ * The resulting chunk must be freed by using IFF_free().
+ *
+ * @param formType Form type describing the purpose of the sub chunks.
+ * @return FORM chunk or NULL, if the memory for the struct can't be allocated
+ */
+IFF_Form *IFF_createForm(const char *formType);
+
+/**
+ * Adds a chunk to the body of the given FORM. This function also increments the
+ * chunk size and chunk length counter.
+ *
+ * @param form An instance of a FORM chunk
+ * @param chunk An arbitrary group or data chunk
+ */
+void IFF_addToForm(IFF_Form *form, IFF_Chunk *chunk);
+
+/**
+ * Reads a form chunk and its sub chunks from a file. The resulting chunk must be
+ * freed by using IFF_free().
+ *
+ * @param file File descriptor of the file
+ * @param chunkSize Size of the chunk data
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return The form struct derived from the file, or NULL if an error has occured
+ */
+IFF_Form *IFF_readForm(FILE *file, const IFF_Long chunkSize, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes a form chunk and its sub chunks to a file.
+ *
+ * @param file File descriptor of the file
+ * @param form An instance of a form chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the FORM has been successfully written, else FALSE
+ */
+int IFF_writeForm(FILE *file, const IFF_Form *form, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the given form type conforms to the IFF specification.
+ *
+ * @param formType A 4 character form identifier
+ * @return TRUE if the form type is valid, else FALSE
+ */
+int IFF_checkFormType(const IFF_ID formType);
+
+/**
+ * Checks whether the form chunk and its sub chunks conform to the IFF specification.
+ *
+ * @param form An instance of a form chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the form is valid, else FALSE.
+ */
+int IFF_checkForm(const IFF_Form *form, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Recursively frees the memory of the sub chunks of the given form chunk.
+ *
+ * @param form An instance of a form chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_freeForm(IFF_Form *form, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Displays a textual representation of the form chunk and its sub chunks on the standard output.
+ *
+ * @param form An instance of a form chunk
+ * @param indentLevel Indent level of the textual representation
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_printForm(const IFF_Form *form, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the given forms' contents is equal to each other.
+ *
+ * @param form1 Form to compare
+ * @param form2 Form to compare
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the given forms are equal, else FALSE
+ */
+int IFF_compareForm(const IFF_Form *form1, const IFF_Form *form2, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Merges two given IFF form arrays in the target array.
+ *
+ * @param target Target form array
+ * @param targetLength Length of the target form array
+ * @param source Source form array
+ * @param sourceLength Length of the source form array
+ * @return A reallocated target form array containing the forms of both the source and target arrays
+ */
+IFF_Form **IFF_mergeFormArray(IFF_Form **target, unsigned int *targetLength, IFF_Form **source, const unsigned int sourceLength);
+
+/**
+ * Returns an array of form structs of the given form types, which are recursively retrieved from the given form.
+ *
+ * @param form An instance of a form chunk
+ * @param formTypes An array of 4 character form type IDs
+ * @param formTypesLength Length of the form types array
+ * @param formsLength Returns the length of the resulting array
+ * @return An array of form structs
+ */
+IFF_Form **IFF_searchFormsInForm(IFF_Form *form, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength);
+
+/**
+ * Recalculates the chunk size of the given form chunk.
+ *
+ * @param form An instance of a form chunk
+ */
+void IFF_updateFormChunkSizes(IFF_Form *form);
+
+/**
+ * Retrieves the chunk with the given chunk ID from the given form.
+ *
+ * @param form An instance of a form chunk
+ * @param chunkId An arbitrary chunk ID
+ * @return The chunk with the given chunk ID, or NULL if the chunk can't be found
+ */
+IFF_Chunk *IFF_getDataChunkFromForm(const IFF_Form *form, const char *chunkId);
+
+/**
+ * Retrieves the chunk with the given chunk ID from the given form.
+ * If the chunk does not exist and the form is member of a list with shared
+ * properties, this function will recursively lookup the chunk from the
+ * shared list properties.
+ *
+ * @param form An instance of a form chunk
+ * @param chunkId An arbitrary chunk ID
+ * @return The chunk with the given chunk ID, or NULL if the chunk can't be found
+ */
+IFF_Chunk *IFF_getChunkFromForm(const IFF_Form *form, const char *chunkId);
+
+/**
+ * Retrieves all the chunks with the given chunk ID from the given form. The resulting array must be freed by using free().
+ *
+ * @param form An instance of a form chunk
+ * @param chunkId An arbitrary chunk ID
+ * @param chunksLength A pointer to a variable in which the length of the array is stored
+ * @return An array with pointers to the chunks with the requested chunk ID, or NULL if there can't be any chunk found
+ */
+IFF_Chunk **IFF_getChunksFromForm(const IFF_Form *form, const char *chunkId, unsigned int *chunksLength);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 263 - 0
ilbm.mod/libiff/src/libiff/group.c

@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "group.h"
+#include <stdlib.h>
+#include "id.h"
+#include "error.h"
+#include "util.h"
+
+void IFF_initGroup(IFF_Group *group, const char *groupType)
+{
+    group->chunkSize = IFF_ID_SIZE; /* We have the group type */
+    IFF_createId(group->groupType, groupType);
+    group->chunkLength = 0;
+    group->chunk = NULL;
+}
+
+IFF_Group *IFF_createGroup(const char *chunkId, const char *groupType)
+{
+    IFF_Group *group = (IFF_Group*)IFF_allocateChunk(chunkId, sizeof(IFF_Group));
+    
+    if(group != NULL)
+	IFF_initGroup(group, groupType);
+    
+    return group;
+}
+
+void IFF_addToGroup(IFF_Group *group, IFF_Chunk *chunk)
+{
+    group->chunk = (IFF_Chunk**)realloc(group->chunk, (group->chunkLength + 1) * sizeof(IFF_Chunk*));
+    group->chunk[group->chunkLength] = chunk;
+    group->chunkLength++;
+    group->chunkSize = IFF_incrementChunkSize(group->chunkSize, chunk);
+    
+    chunk->parent = group;
+}
+
+IFF_Group *IFF_readGroup(io_context *context, const char *chunkId, const IFF_Long chunkSize, const char *groupTypeName, const int groupTypeIsFormType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_ID groupType;
+    IFF_Group *group;
+    char *formType;
+    
+    /* Read group type */
+    if(!IFF_readId(context, groupType, chunkId, groupTypeName))
+	return NULL;
+
+    /* Create new group */
+    group = IFF_createGroup(chunkId, groupType);
+
+    /* Determine form type */
+    if(groupTypeIsFormType)
+	formType = groupType;
+    else
+	formType = NULL;
+    
+    /* Keep parsing sub chunks until we have read all bytes */
+    
+    while(group->chunkSize < chunkSize)
+    {
+	/* Read sub chunk */
+	IFF_Chunk *chunk = IFF_readChunk(context, formType, extension, extensionLength);
+	
+	if(chunk == NULL)
+	{
+	    IFF_error("Error while reading chunk!\n");
+	    IFF_freeChunk((IFF_Chunk*)group, formType, extension, extensionLength);
+	    return NULL;
+	}
+	
+	/* Add chunk to the group */
+	IFF_addToGroup(group, chunk);
+    }
+    
+    /*
+     * Set the chunk size to what we have read. This is mandatory according to
+     * the IFF specification, because we must respect this even when it's
+     * truncated
+     */
+    group->chunkSize = chunkSize;
+    
+    /* Return the resulting group */
+    return group;
+}
+
+int IFF_writeGroupSubChunks(FILE *file, const IFF_Group *group, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    unsigned int i;
+    
+    for(i = 0; i < group->chunkLength; i++)
+    {
+	if(!IFF_writeChunk(file, group->chunk[i], formType, extension, extensionLength))
+	{
+	    IFF_error("Error writing chunk!\n");
+	    return FALSE;
+	}
+    }
+    
+    return TRUE;
+}
+
+int IFF_writeGroup(FILE *file, const IFF_Group *group, const char *formType, const char *groupTypeName, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    if(!IFF_writeId(file, group->groupType, group->chunkId, groupTypeName))
+	return FALSE;
+
+    if(!IFF_writeGroupSubChunks(file, group, formType, extension, extensionLength))
+	return FALSE;
+    
+    return TRUE;
+}
+
+int IFF_checkGroupChunkSize(const IFF_Group *group, const IFF_Long chunkSize)
+{
+    if(chunkSize == group->chunkSize)
+	return TRUE;
+    else
+    {
+	IFF_error("Chunk size mismatch! ");
+	IFF_errorId(group->chunkId);
+	IFF_error(" size: %d, while body has: %d\n", group->chunkSize, chunkSize);
+	return FALSE;
+    }
+}
+
+IFF_Long IFF_checkGroupSubChunks(const IFF_Group *group, int (*subChunkCheck) (const IFF_Group *group, const IFF_Chunk *subChunk), const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    unsigned int i;
+    IFF_Long chunkSize = 0;
+    
+    for(i = 0; i < group->chunkLength; i++)
+    {
+	IFF_Chunk *subChunk = group->chunk[i];
+	
+	if(!subChunkCheck(group, subChunk))
+	    return -1;
+	
+	/* Check validity of the sub chunk */
+	if(!IFF_checkChunk(subChunk, formType, extension, extensionLength))
+	    return -1;
+	
+	chunkSize = IFF_incrementChunkSize(chunkSize, subChunk);
+    }
+    
+    return chunkSize;
+}
+
+int IFF_checkGroup(const IFF_Group *group, int (*groupTypeCheck) (const char *groupType), int (*subChunkCheck) (const IFF_Group *group, const IFF_Chunk *subChunk), const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_Long chunkSize;
+    
+    if(!groupTypeCheck(group->groupType))
+	return FALSE;
+    
+    if((chunkSize = IFF_checkGroupSubChunks(group, subChunkCheck, formType, extension, extensionLength)) == -1)
+	return FALSE;
+    
+    chunkSize += IFF_ID_SIZE;
+    
+    if(!IFF_checkGroupChunkSize(group, chunkSize))
+	return FALSE;
+    
+    return TRUE;
+}
+
+void IFF_freeGroup(IFF_Group *group, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    unsigned int i;
+    
+    for(i = 0; i < group->chunkLength; i++)
+	IFF_freeChunk(group->chunk[i], formType, extension, extensionLength);
+
+    free(group->chunk);
+}
+
+void IFF_printGroupType(const char *groupTypeName, const char *groupType, const unsigned int indentLevel)
+{
+    IFF_printIndent(stdout, indentLevel, "%s = '", groupTypeName);
+    IFF_printId(groupType);
+    printf("';\n");
+}
+
+void IFF_printGroupSubChunks(const IFF_Group *group, const unsigned int indentLevel, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    unsigned int i;
+
+    IFF_printIndent(stdout, indentLevel, "[\n");
+
+    for(i = 0; i < group->chunkLength; i++)
+	IFF_printChunk((IFF_Chunk*)group->chunk[i], indentLevel + 1, formType, extension, extensionLength);
+	
+    IFF_printIndent(stdout, indentLevel, "];\n");
+}
+
+void IFF_printGroup(const IFF_Group *group, const unsigned int indentLevel, const char *formType, const char *groupTypeName, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_printGroupType(groupTypeName, group->groupType, indentLevel);
+    IFF_printGroupSubChunks(group, indentLevel, formType, extension, extensionLength);
+}
+
+int IFF_compareGroup(const IFF_Group *group1, const IFF_Group *group2, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    if((IFF_compareId(group1->groupType, group2->groupType) == 0) && (group1->chunkLength == group2->chunkLength))
+    {
+	unsigned int i;
+	
+	for(i = 0; i < group1->chunkLength; i++)
+	{
+	    if(!IFF_compareChunk(group1->chunk[i], group2->chunk[i], formType, extension, extensionLength))
+		return FALSE;
+	}
+	
+	return TRUE;
+    }
+    else
+	return FALSE;
+}
+
+IFF_Form **IFF_searchFormsInGroup(IFF_Group *group, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength)
+{
+    IFF_Form **forms = NULL;
+    unsigned int i;
+
+    *formsLength = 0;
+
+    for(i = 0; i < group->chunkLength; i++)
+    {
+        unsigned int resultLength;
+        IFF_Form **result = IFF_searchFormsFromArray(group->chunk[i], formTypes, formTypesLength, &resultLength);
+
+        forms = IFF_mergeFormArray(forms, formsLength, result, resultLength);
+    }
+
+    return forms;
+}
+
+void IFF_updateGroupChunkSizes(IFF_Group *group)
+{
+    unsigned int i;
+
+    group->chunkSize = IFF_ID_SIZE;
+
+    for(i = 0; i < group->chunkLength; i++)
+        group->chunkSize = IFF_incrementChunkSize(group->chunkSize, group->chunk[i]);
+}

+ 237 - 0
ilbm.mod/libiff/src/libiff/group.h

@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_GROUP_H
+#define __IFF_GROUP_H
+
+typedef struct IFF_Group IFF_Group;
+
+#include <stdio.h>
+#include "ifftypes.h"
+#include "chunk.h"
+#include "form.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief An abstract group chunk, which contains all common properties of the compound chunk types. This chunk type should never be used directly.
+ */
+struct IFF_Group
+{
+    /** Pointer to the parent group chunk, in which this chunk is located. The parent points to NULL if there is no parent. */
+    IFF_Group *parent;
+
+    /** Contains a 4 character ID of this chunk */
+    IFF_ID chunkId;
+    
+    /** Contains the size of the chunk data in bytes */
+    IFF_Long chunkSize;
+    
+    /** Could be either a formType or a contentsType */
+    IFF_ID groupType;
+    
+    /** Contains the number of sub chunks stored in this group chunk */
+    unsigned int chunkLength;
+    
+    /** An array of chunk pointers referring to the sub chunks */
+    IFF_Chunk **chunk;
+};
+
+/**
+ * Initializes the members of the group chunk instances with default values.
+ *
+ * @param group A group chunk instance
+ * @param groupType A group type ID
+ */
+void IFF_initGroup(IFF_Group *group, const char *groupType);
+
+/**
+ * Creates a new group chunk instance with the chunk id and group type.
+ * The resulting chunk must be freed by using IFF_free().
+ *
+ * @param chunkId A 4 character chunk id.
+ * @param groupType Type describing the purpose of the sub chunks.
+ * @return Group chunk or NULL, if the memory for the struct can't be allocated
+ */
+IFF_Group *IFF_createGroup(const char *chunkId, const char *groupType);
+
+/**
+ * Adds a chunk to the body of the given group. This function also increments the
+ * chunk size and chunk length counter.
+ *
+ * @param group An instance of a group chunk
+ * @param chunk An arbitrary group or data chunk
+ */
+void IFF_addToGroup(IFF_Group *group, IFF_Chunk *chunk);
+
+/**
+ * Reads a group chunk and its sub chunks from a file. The resulting chunk must be
+ * freed by using IFF_free().
+ *
+ * @param file File descriptor of the file
+ * @param chunkId A 4 character chunk id
+ * @param chunkSize Size of the chunk data
+ * @param groupTypeName Specifies what the group type is called. Could be 'formType' or 'contentsType'
+ * @param groupTypeIsFormType Indicates whether the groupType represents a formType
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return The group struct derived from the file, or NULL if an error has occured
+ */
+IFF_Group *IFF_readGroup(io_context *context, const char *chunkId, const IFF_Long chunkSize, const char *groupTypeName, const int groupTypeIsFormType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes all sub chunks inside a group to a file.
+ *
+ * @param file File descriptor of the file
+ * @param group An instance of a group chunk
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the sub chunks have been successfully written, else FALSE
+ */
+int IFF_writeGroupSubChunks(FILE *file, const IFF_Group *group, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes a group chunk and its sub chunks to a file.
+ *
+ * @param file File descriptor of the file
+ * @param group An instance of a group chunk
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param groupTypeName Specifies what the group type is called. Could be 'formType' or 'contentsType'
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the group has been successfully written, else FALSE
+ */
+int IFF_writeGroup(FILE *file, const IFF_Group *group, const char *formType, const char *groupTypeName, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the given chunk size matches the chunk size of the group
+ *
+ * @param group An instance of a group chunk
+ * @param chunkSize A chunk size
+ * @return TRUE if the chunk sizes are equal, else FALSE
+ */
+int IFF_checkGroupChunkSize(const IFF_Group *group, const IFF_Long chunkSize);
+
+/**
+ * Checks whether the group sub chunks are valid
+ *
+ * @param group An instance of a group chunk
+ * @param subChunkCheck Pointer to a function, which checks an individual sub chunk for its validity
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return The size of the sub chunks together, or -1 if a failure has occured
+ */
+IFF_Long IFF_checkGroupSubChunks(const IFF_Group *group, int (*subChunkCheck) (const IFF_Group *group, const IFF_Chunk *subChunk), const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the group chunk and its sub chunks conform to the IFF specification.
+ *
+ * @param group An instance of a group chunk
+ * @param groupTypeCheck Pointer to a function, which checks the groupType for its validity
+ * @param subChunkCheck Pointer to a function, which checks an individual sub chunk for its validity
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the form is valid, else FALSE.
+ */
+int IFF_checkGroup(const IFF_Group *group, int (*groupTypeCheck) (const char *groupType), int (*subChunkCheck) (const IFF_Group *group, const IFF_Chunk *subChunk), const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Recursively frees the memory of the sub chunks of the given group chunk.
+ *
+ * @param group An instance of a group chunk
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_freeGroup(IFF_Group *group, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Displays the group type on the standard output.
+ *
+ * @param groupTypeName Specifies what the group type is called. Could be 'formType' or 'contentsType'
+ * @param groupType A group type ID
+ * @param indentLevel Indent level of the textual representation
+ */
+void IFF_printGroupType(const char *groupTypeName, const char *groupType, const unsigned int indentLevel);
+
+/**
+ * Displays a textual representation of the sub chunks on the standard output.
+ *
+ * @param group An instance of a group chunk
+ * @param indentLevel Indent level of the textual representation
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_printGroupSubChunks(const IFF_Group *group, const unsigned int indentLevel, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Displays a textual representation of the group chunk and its sub chunks on the standard output.
+ *
+ * @param group An instance of a group chunk
+ * @param indentLevel Indent level of the textual representation
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param groupTypeName Specifies what the group type is called. Could be 'formType' or 'contentsType'
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_printGroup(const IFF_Group *group, const unsigned int indentLevel, const char *formType, const char *groupTypeName, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the given group chunks' contents is equal to each other.
+ *
+ * @param group1 Group to compare
+ * @param group2 Group to compare
+ * @param formType Form type id describing in which FORM the sub chunk is located. NULL is used for sub chunks in other group chunks.
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the given groups are equal, else FALSE
+ */
+int IFF_compareGroup(const IFF_Group *group1, const IFF_Group *group2, const char *formType, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Returns an array of form structs of the given form types, which are recursively retrieved from the given group.
+ *
+ * @param group An instance of a group chunk
+ * @param formTypes An array of 4 character form type IDs
+ * @param formTypesLength Length of the form types array
+ * @param formsLength Returns the length of the resulting array
+ * @return An array of form structs
+ */
+IFF_Form **IFF_searchFormsInGroup(IFF_Group *group, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength);
+
+/**
+ * Recalculates the chunk size of the given group chunk.
+ *
+ * @param group An instance of a group chunk
+ */
+void IFF_updateGroupChunkSizes(IFF_Group *group);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 90 - 0
ilbm.mod/libiff/src/libiff/id.c

@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "id.h"
+#include <string.h>
+#include "error.h"
+
+void IFF_createId(IFF_ID id, const char *idString)
+{
+    strncpy(id, idString, IFF_ID_SIZE);
+}
+
+int IFF_compareId(const IFF_ID id1, const char* id2)
+{
+    return strncmp(id1, id2, IFF_ID_SIZE);
+}
+
+int IFF_readId(io_context *context, IFF_ID id, const IFF_ID chunkId, const char *attributeName)
+{
+    if((context->io.read)(context->userData,id,IFF_ID_SIZE) == IFF_ID_SIZE)
+	return TRUE;
+    else
+    {
+	IFF_readError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_writeId(FILE *file, const IFF_ID id, const IFF_ID chunkId, const char *attributeName)
+{
+    if(fwrite(id, IFF_ID_SIZE, 1, file) == 1)
+	return TRUE;
+    else
+    {
+	IFF_writeError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_checkId(const IFF_ID id)
+{
+    unsigned int i;
+    
+    /* ID characters must be between 0x20 and 0x7e */
+    
+    for(i = 0; i < IFF_ID_SIZE; i++)
+    {
+	if(id[i] < 0x20 || id[i] > 0x7e)
+	{
+	    IFF_error("Illegal character: '%c' in ID!\n", id[i]);
+	    return FALSE;
+	}
+    }
+    
+    /* Spaces may not precede an ID, trailing spaces are ok */
+    
+    if(id[0] == ' ')
+    {
+	IFF_error("Spaces may not precede an ID!\n");
+	return FALSE;
+    }
+    
+    return TRUE;
+}
+
+void IFF_printId(const IFF_ID id)
+{
+    unsigned int i;
+    
+    for(i = 0; i < IFF_ID_SIZE; i++)
+	printf("%c", id[i]);
+}

+ 90 - 0
ilbm.mod/libiff/src/libiff/id.h

@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_ID_H
+#define __IFF_ID_H
+
+#include <stdio.h>
+#include "ifftypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a 4 character ID from a string.
+ *
+ * @param id A 4 character IFF id
+ * @param idString String containing a 4 character ID
+ */
+void IFF_createId(IFF_ID id, const char *idString);
+
+/**
+ * Compares two IFF ids
+ *
+ * @param id1 An IFF ID to compare
+ * @param id2 An IFF ID to compare
+ * @return 0 if the IDs are equal, a value lower than 0 if id1 is lower than id2, a value higher than 1 if id1 is higher than id2
+ */
+int IFF_compareId(const IFF_ID id1, const char* id2);
+
+/**
+ * Reads an IFF id from a file
+ *
+ * @param file File descriptor of the file
+ * @param id A 4 character IFF id
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the ID is succesfully read, else FALSE
+ */
+int IFF_readId(io_context *context, IFF_ID id, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Writes an IFF id to a file
+ *
+ * @param file File descriptor of the file
+ * @param id A 4 character IFF id
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the ID is succesfully written, else FALSE
+ */
+int IFF_writeId(FILE *file, const IFF_ID id, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Checks whether an IFF id is valid
+ *
+ * @param id A 4 character IFF id
+ * @return TRUE if the IFF id is valid, else FALSE
+ */
+int IFF_checkId(const IFF_ID id);
+
+/**
+ * Prints an IFF id
+ *
+ * @param id A 4 character IFF id
+ */
+void IFF_printId(const IFF_ID id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 154 - 0
ilbm.mod/libiff/src/libiff/iff.c

@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "iff.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "id.h"
+#include "util.h"
+#include "error.h"
+
+
+static int IFF_FILE_read(void *file, char *data, int size)
+{
+    return (int) fread(data,1,size,(FILE*) file);
+}
+
+static int IFF_FILE_write(void *file, char *data, int size)
+{
+    return (int) fwrite(data, 1, size, (FILE*) file);
+}
+
+static int IFF_FILE_eof(void *file)
+{
+    return feof((FILE*) file) || ferror((FILE *) file);
+}
+
+static io_callbacks IFF_FILE_callbacks =
+{
+    IFF_FILE_read,
+    IFF_FILE_write,
+    IFF_FILE_eof,
+};
+
+IFF_Chunk *IFF_readIo(io_context *context, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_Chunk *chunk;
+    int byte;
+    
+    /* Read the chunk */
+    chunk = IFF_readChunk(context, NULL, extension, extensionLength);
+    
+    if(chunk == NULL)
+    {
+        IFF_error("ERROR: cannot open main chunk!\n");
+        return NULL;
+    }
+    
+    /* We should have reached the EOF now */
+    if((context->io.eof)(context->userData) == 0)
+        IFF_error("WARNING: Trailing IFF contents found!\n");
+
+    /* Return the parsed main chunk */
+    return chunk;
+}
+
+IFF_Chunk *IFF_readFd(FILE *file, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    io_context context;
+    context.userData = file;
+    context.io = IFF_FILE_callbacks;
+
+    return IFF_readIo(&context, extension, extensionLength);
+}
+
+IFF_Chunk *IFF_read(const char *filename, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_Chunk *chunk;
+    FILE *file = fopen(filename, "rb");
+    
+    /* Open the IFF file */
+    if(file == NULL)
+    {
+        IFF_error("ERROR: cannot open file: %s\n", filename);
+        return NULL;
+    }
+
+    /* Parse the main chunk */
+    chunk = IFF_readFd(file, extension, extensionLength);
+    
+    /* Close the file */
+    fclose(file);
+
+    /* Return the chunk */
+    return chunk;
+}
+
+int IFF_writeFd(FILE *file, const IFF_Chunk *chunk, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_writeChunk(file, chunk, NULL, extension, extensionLength);
+}
+
+int IFF_write(const char *filename, const IFF_Chunk *chunk, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    int status;
+    FILE *file = fopen(filename, "wb");
+    
+    if(file == NULL)
+    {
+        IFF_error("ERROR: cannot open file: %s\n", filename);
+        return FALSE;
+    }
+    
+    status = IFF_writeFd(file, chunk, extension, extensionLength);
+    fclose(file);
+    return status;
+}
+
+void IFF_free(IFF_Chunk *chunk, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_freeChunk(chunk, NULL, extension, extensionLength);
+}
+
+int IFF_check(const IFF_Chunk *chunk, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    /* The main chunk must be of ID: FORM, CAT or LIST */
+    
+    if(IFF_compareId(chunk->chunkId, "FORM") != 0 &&
+       IFF_compareId(chunk->chunkId, "CAT ") != 0 &&
+       IFF_compareId(chunk->chunkId, "LIST") != 0)
+    {
+        IFF_error("Not a valid IFF-85 file: First bytes should start with either: 'FORM', 'CAT ' or 'LIST'\n");
+        return FALSE;
+    }
+    else
+        return IFF_checkChunk(chunk, NULL, extension, extensionLength);
+}
+
+void IFF_print(const IFF_Chunk *chunk, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_printChunk(chunk, indentLevel, NULL, extension, extensionLength);
+}
+
+int IFF_compare(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_compareChunk(chunk1, chunk2, NULL, extension, extensionLength);
+}

+ 128 - 0
ilbm.mod/libiff/src/libiff/iff.h

@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_H
+#define __IFF_H
+
+#include "ifftypes.h"
+#include "chunk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Reads an IFF file from a given io context. The resulting chunk must be freed using IFF_free().
+ *
+ * @param context The io context
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return A chunk hierarchy derived from the IFF file, or NULL if an error occurs
+ */
+IFF_Chunk *IFF_readIo(io_context *context, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Reads an IFF file from a given file descriptor. The resulting chunk must be freed using IFF_free().
+ *
+ * @param file File descriptor of the file
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return A chunk hierarchy derived from the IFF file, or NULL if an error occurs
+ */
+IFF_Chunk *IFF_readFd(FILE *file, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Reads an IFF file from a file with the given filename. The resulting chunk must be freed using IFF_free().
+ *
+ * @param filename Filename of the file
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return A chunk hierarchy derived from the IFF file, or NULL if an error occurs
+ */
+IFF_Chunk *IFF_read(const char *filename, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes an IFF file to a given file descriptor.
+ *
+ * @param file File descriptor of the file
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the file has been successfully written, else FALSE
+ */
+int IFF_writeFd(FILE *file, const IFF_Chunk *chunk, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes an IFF file to a file with the given filename.
+ *
+ * @param filename Filename of the file
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the file has been successfully written, else FALSE
+ */
+int IFF_write(const char *filename, const IFF_Chunk *chunk, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Frees an IFF chunk hierarchy from memory.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_free(IFF_Chunk *chunk, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether an IFF file conforms to the IFF specification.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the IFF file conforms to the IFF specification, else FALSE
+ */
+int IFF_check(const IFF_Chunk *chunk, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Displays a textual representation of an IFF file on the standard output.
+ *
+ * @param chunk A chunk hierarchy representing an IFF file
+ * @param indentLevel Indent level of the textual representation
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_print(const IFF_Chunk *chunk, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether two given IFF files are equal.
+ *
+ * @param chunk1 Chunk hierarchy to compare
+ * @param chunk2 Chunk hierarchy to compare
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the given chunk hierarchies are equal, else FALSE
+ */
+int IFF_compare(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2, const IFF_Extension *extension, const unsigned int extensionLength);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 66 - 0
ilbm.mod/libiff/src/libiff/ifftypes.h

@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_IFFTYPES_H
+#define __IFF_IFFTYPES_H
+
+#define IFF_ID_SIZE 4
+
+/** A signed byte */
+typedef char IFF_Byte;
+
+/** An unsigned byte */
+typedef unsigned char IFF_UByte;
+
+/** A 16-bit signed type */
+typedef short IFF_Word;
+
+/** A 16-bit unsigned type */
+typedef unsigned short IFF_UWord;
+
+/** A 32-bit signed type */
+typedef int IFF_Long;
+
+/** A 32-bit unsigned type */
+typedef unsigned int IFF_ULong;
+
+/** A 4 byte ID type */
+typedef char IFF_ID[IFF_ID_SIZE];
+
+typedef struct
+{
+   int (*read) (void *userData, char *data, int size);
+   int (*write) (void *userData, char *data, int size);
+   int (*eof) (void *userData);
+} io_callbacks;
+
+typedef struct
+{
+   io_callbacks io;
+   void *userData;
+} io_context;
+
+#define TRUE 1
+#define FALSE 0
+
+#define IFF_BIG_ENDIAN 0
+
+#endif

+ 53 - 0
ilbm.mod/libiff/src/libiff/ifftypes.h.in

@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_IFFTYPES_H
+#define __IFF_IFFTYPES_H
+
+#define IFF_ID_SIZE 4
+
+/** A signed byte */
+typedef char IFF_Byte;
+
+/** An unsigned byte */
+typedef unsigned char IFF_UByte;
+
+/** A 16-bit signed type */
+typedef short IFF_Word;
+
+/** A 16-bit unsigned type */
+typedef unsigned short IFF_UWord;
+
+/** A 32-bit signed type */
+typedef int IFF_Long;
+
+/** A 32-bit unsigned type */
+typedef unsigned int IFF_ULong;
+
+/** A 4 byte ID type */
+typedef char IFF_ID[IFF_ID_SIZE];
+
+#define TRUE 1
+#define FALSE 0
+
+#define IFF_BIG_ENDIAN @IFF_BIG_ENDIAN@
+
+#endif

+ 255 - 0
ilbm.mod/libiff/src/libiff/io.c

@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "io.h"
+#include "error.h"
+
+int IFF_readUByte(io_context * context, IFF_UByte *value, const IFF_ID chunkId, const char *attributeName)
+{
+    if((context->io.eof)(context->userData))
+    {
+    IFF_readError(chunkId, attributeName);
+	return FALSE;
+    }
+    char byte;
+
+    if((context->io.read)(context->userData,&byte,1) == 0)
+    {
+    IFF_readError(chunkId, attributeName);
+	return FALSE;
+    }
+    else
+    {
+	*value = byte;
+	return TRUE;
+    }
+}
+
+int IFF_writeUByte(FILE *file, const IFF_UByte value, const IFF_ID chunkId, const char *attributeName)
+{
+    if(fputc(value, file) == EOF)
+    {
+	IFF_writeError(chunkId, attributeName);
+	return FALSE;
+    }
+    else
+	return TRUE;
+}
+
+int IFF_readUWord(io_context * context, IFF_UWord *value, const IFF_ID chunkId, const char *attributeName)
+{
+    IFF_UWord readUWord;
+    
+    if((context->io.read)(context->userData,&readUWord,sizeof(IFF_UWord)) > 0)
+    {
+#if IFF_BIG_ENDIAN == 1
+	*value = readUWord;
+#else
+	/* Byte swap it */
+	*value = (readUWord & 0xff) << 8 | (readUWord & 0xff00) >> 8;
+#endif
+	
+	return TRUE;
+    }
+    else
+    {
+	IFF_readError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_writeUWord(FILE *file, const IFF_UWord value, const IFF_ID chunkId, const char *attributeName)
+{
+#if IFF_BIG_ENDIAN == 1
+    IFF_UWord writeUWord = value;
+#else
+    /* Byte swap it */
+    IFF_UWord writeUWord = (value & 0xff) << 8 | (value & 0xff00) >> 8;
+#endif
+
+    if(fwrite(&writeUWord, sizeof(IFF_UWord), 1, file) == 1)
+	return TRUE;
+    else
+    {
+	IFF_writeError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_readWord(io_context * context, IFF_Word *value, const IFF_ID chunkId, const char *attributeName)
+{
+    IFF_Word readWord;
+    
+    if((context->io.read)(context->userData,&readWord,sizeof(IFF_Word)) > 0)
+    {
+#if IFF_BIG_ENDIAN == 1
+	*value = readWord;
+#else
+	/* Byte swap it */
+	*value = (readWord & 0xff) << 8 | (readWord & 0xff00) >> 8;
+#endif
+	return TRUE;
+    }
+    else
+    {
+	IFF_readError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_writeWord(FILE *file, const IFF_Word value, const IFF_ID chunkId, const char *attributeName)
+{
+#if IFF_BIG_ENDIAN == 1
+    IFF_Word writeWord = value;
+#else
+    IFF_Word writeWord = (value & 0xff) << 8 | (value & 0xff00) >> 8;
+#endif
+
+    if(fwrite(&writeWord, sizeof(IFF_Word), 1, file) == 1)
+	return TRUE;
+    else
+    {
+	IFF_writeError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_readULong(io_context * context, IFF_ULong *value, const IFF_ID chunkId, const char *attributeName)
+{
+    IFF_ULong readValue;
+    
+    if((context->io.read)(context->userData,&readValue,sizeof(IFF_ULong)) > 0)
+    {
+#if IFF_BIG_ENDIAN == 1
+	*value = readValue;
+#else
+	/* Byte swap it */
+	*value = (readValue & 0xff) << 24 | (readValue & 0xff00) << 8 | (readValue & 0xff0000) >> 8 | (readValue & 0xff000000) >> 24;
+#endif
+	return TRUE;
+    }
+    else
+    {
+	IFF_readError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_writeULong(FILE *file, const IFF_ULong value, const IFF_ID chunkId, const char *attributeName)
+{
+#if IFF_BIG_ENDIAN == 1
+    IFF_ULong writeValue = value;
+#else
+    /* Byte swap it */
+    IFF_ULong writeValue = (value & 0xff) << 24 | (value & 0xff00) << 8 | (value & 0xff0000) >> 8 | (value & 0xff000000) >> 24;
+#endif
+
+    if(fwrite(&writeValue, sizeof(IFF_ULong), 1, file) == 1)
+	return TRUE;
+    else
+    {
+	IFF_writeError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_readLong(io_context * context, IFF_Long *value, const IFF_ID chunkId, const char *attributeName)
+{
+    IFF_Long readValue;
+    
+    if((context->io.read)(context->userData,&readValue,sizeof(IFF_Long)) > 0)
+    {
+#if IFF_BIG_ENDIAN == 1
+	*value = readValue;
+#else
+	/* Byte swap it */
+	*value = (readValue & 0xff) << 24 | (readValue & 0xff00) << 8 | (readValue & 0xff0000) >> 8 | (readValue & 0xff000000) >> 24;
+#endif
+	return TRUE;
+    }
+    else
+    {
+	IFF_readError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_writeLong(FILE *file, const IFF_Long value, const IFF_ID chunkId, const char *attributeName)
+{
+#if IFF_BIG_ENDIAN == 1
+    IFF_Long writeValue = value;
+#else
+    /* Byte swap it */
+    IFF_Long writeValue = (value & 0xff) << 24 | (value & 0xff00) << 8 | (value & 0xff0000) >> 8 | (value & 0xff000000) >> 24;
+#endif
+
+    if(fwrite(&writeValue, sizeof(IFF_Long), 1, file) == 1)
+	return TRUE;
+    else
+    {
+	IFF_writeError(chunkId, attributeName);
+	return FALSE;
+    }
+}
+
+int IFF_readPaddingByte(io_context * context, const IFF_Long chunkSize, const IFF_ID chunkId)
+{
+    if(chunkSize % 2 != 0) /* Check whether the chunk size is an odd number */
+    {
+        int err = (context->io.eof)(context->userData);
+        char byte;
+
+        if(!err)
+        {
+            err = (context->io.read)(context->userData,&byte,1) == 0; /* Read padding byte */
+        }
+	
+        if(err) /* We shouldn't have reached the EOF yet */
+        {
+    	    IFF_error("Unexpected end of file, while reading padding byte of '");
+    	    IFF_errorId(chunkId);
+    	    IFF_error("'\n");
+	    return FALSE;
+	}
+	else if(byte != 0) /* Normally, a padding byte is 0, warn if this is not the case */
+	    IFF_error("WARNING: Padding byte is non-zero!\n");
+    }
+    
+    return TRUE;
+}
+
+int IFF_writePaddingByte(FILE *file, const IFF_Long chunkSize, const IFF_ID chunkId)
+{
+    if(chunkSize % 2 != 0) /* Check whether the chunk size is an odd number */
+    {
+	if(fputc('\0', file) == EOF)
+	{
+	    IFF_error("Cannot write padding byte of '");
+	    IFF_errorId(chunkId);
+	    IFF_error("'\n");
+	    return FALSE;
+	}
+	else
+	    return TRUE;
+    }
+    
+    return TRUE;
+}

+ 166 - 0
ilbm.mod/libiff/src/libiff/io.h

@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_IO_H
+#define __IFF_IO_H
+
+#include <stdio.h>
+#include "ifftypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Reads an unsigned byte from a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value read from the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully read, else FALSE
+ */
+int IFF_readUByte(io_context *context, IFF_UByte *value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Writes an unsigned byte to a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value written to the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully written, else FALSE
+ */
+int IFF_writeUByte(FILE *file, const IFF_UByte value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Reads an unsigned word from a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value read from the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully read, else FALSE
+ */
+int IFF_readUWord(io_context *context, IFF_UWord *value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Writes an unsigned word to a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value written to the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully written, else FALSE
+ */
+int IFF_writeUWord(FILE *file, const IFF_UWord value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Reads a signed word from a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value read from the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully read, else FALSE
+ */
+int IFF_readWord(io_context *context, IFF_Word *value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Writes a signed word to a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value written to the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully written, else FALSE
+ */
+int IFF_writeWord(FILE *file, const IFF_Word value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Reads an unsigned long from a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value read from the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully read, else FALSE
+ */
+int IFF_readULong(io_context *context, IFF_ULong *value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Writes an unsigned long to a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value read from the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully written, else FALSE
+ */
+int IFF_writeULong(FILE* file, const IFF_ULong value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Reads a signed long from a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value read from the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully read, else FALSE
+ */
+int IFF_readLong(io_context *context, IFF_Long *value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Writes a signed long to a file.
+ *
+ * @param file File descriptor of the file
+ * @param value Value read from the file
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @param attributeName The name of the attribute that is examined (used for error reporting)
+ * @return TRUE if the value has been successfully written, else FALSE
+ */
+int IFF_writeLong(FILE* file, const IFF_Long value, const IFF_ID chunkId, const char *attributeName);
+
+/**
+ * Reads a padding byte from a chunk with an odd size.
+ *
+ * @param file File descriptor of the file
+ * @param chunkSize Size of the chunk in bytes
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @return TRUE if the byte has been successfully read, else FALSE
+ */
+int IFF_readPaddingByte(io_context *context, const IFF_Long chunkSize, const IFF_ID chunkId);
+
+/**
+ * Writes a padding byte to a chunk with an odd size.
+ *
+ * @param file File descriptor of the file
+ * @param chunkSize Size of the chunk in bytes
+ * @param chunkId A 4 character chunk id in which the operation takes place (used for error reporting)
+ * @return TRUE if the byte has been successfully written, else FALSE
+ */
+int IFF_writePaddingByte(FILE *file, const IFF_Long chunkSize, const IFF_ID chunkId);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 120 - 0
ilbm.mod/libiff/src/libiff/libiff.def

@@ -0,0 +1,120 @@
+LIBRARY    libiff
+EXPORTS
+	IFF_readFd                @1
+	IFF_read                  @2
+	IFF_writeFd               @3
+	IFF_write                 @4
+	IFF_free                  @5
+	IFF_check                 @6
+	IFF_print                 @7
+	IFF_compare               @8
+	IFF_createCAT             @9
+	IFF_addToCAT              @10
+	IFF_readCAT               @11
+	IFF_writeCAT              @12
+	IFF_checkCATSubChunk      @13
+	IFF_checkCAT              @14
+	IFF_freeCAT               @15
+	IFF_printCAT              @16
+	IFF_compareCAT            @17
+	IFF_searchFormsInCAT      @18
+	IFF_updateCATChunkSizes   @19
+	IFF_allocateChunk         @20
+	IFF_readChunk             @21
+	IFF_writeChunk            @22
+	IFF_checkChunk            @23
+	IFF_freeChunk             @24
+	IFF_printChunk            @25
+	IFF_compareChunk          @26
+	IFF_searchForms           @27
+	IFF_searchFormsFromArray  @28
+	IFF_incrementChunkSize    @29
+	IFF_updateChunkSizes      @30
+	IFF_errorCallbackStderr   @31
+	IFF_error                 @32
+	IFF_errorId               @33
+	IFF_readError             @34
+	IFF_writeError            @35
+	IFF_findFormExtension     @36
+	IFF_createForm            @37
+	IFF_addToForm             @38
+	IFF_readForm              @39
+	IFF_writeForm             @40
+	IFF_checkFormType         @41
+	IFF_checkForm             @42
+	IFF_freeForm              @43
+	IFF_printForm             @44
+	IFF_compareForm           @45
+	IFF_mergeFormArray        @46
+	IFF_searchFormsInForm     @47
+	IFF_updateFormChunkSizes  @48
+	IFF_getDataChunkFromForm  @49
+	IFF_getChunkFromForm      @50
+	IFF_getChunksFromForm     @51
+	IFF_initGroup             @52
+	IFF_createGroup           @53
+	IFF_addToGroup            @54
+	IFF_readGroup             @55
+	IFF_writeGroupSubChunks   @56
+	IFF_writeGroup            @57
+	IFF_checkGroupChunkSize   @58
+	IFF_checkGroupSubChunks   @59
+	IFF_checkGroup            @60
+	IFF_freeGroup             @61
+	IFF_printGroupType        @62
+	IFF_printGroupSubChunks   @63
+	IFF_printGroup            @64
+	IFF_compareGroup          @65
+	IFF_searchFormsInGroup    @66
+	IFF_updateGroupChunkSizes @67
+	IFF_createId              @68
+	IFF_compareId             @69
+	IFF_readId                @70
+	IFF_writeId               @71
+	IFF_checkId               @72
+	IFF_printId               @73
+	IFF_readUByte             @74
+	IFF_writeUByte            @75
+	IFF_readUWord             @76
+	IFF_writeUWord            @77
+	IFF_readWord              @78
+	IFF_writeWord             @79
+	IFF_readULong             @80
+	IFF_writeULong            @81
+	IFF_readLong              @82
+	IFF_writeLong             @83
+	IFF_readPaddingByte       @84
+	IFF_writePaddingByte      @85
+	IFF_createList            @86
+	IFF_addPropToList         @87
+	IFF_addToList             @88
+	IFF_readList              @89
+	IFF_writeList             @90
+	IFF_checkList             @91
+	IFF_freeList              @92
+	IFF_printList             @93
+	IFF_compareList           @94
+	IFF_searchFormsInList     @95
+	IFF_updateListChunkSizes  @96
+	IFF_getPropFromList       @97
+	IFF_createProp            @98
+	IFF_addToProp             @99
+	IFF_readProp              @100
+	IFF_writeProp             @101
+	IFF_checkProp             @102
+	IFF_freeProp              @103
+	IFF_printProp             @104
+	IFF_compareProp           @105
+	IFF_updatePropChunkSizes  @106
+	IFF_getChunkFromProp      @107
+	IFF_createRawChunk        @108
+	IFF_setRawChunkData       @109
+	IFF_setTextData           @110
+	IFF_readRawChunk          @111
+	IFF_writeRawChunk         @112
+	IFF_freeRawChunk          @113
+	IFF_printText             @114
+	IFF_printRaw              @115
+	IFF_printRawChunk         @116
+	IFF_compareRawChunk       @117
+	IFF_printIndent           @118

+ 112 - 0
ilbm.mod/libiff/src/libiff/libiff.vcxproj

@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{5857969C-CEB8-4BF3-BACB-81D7CE0FC654}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v120</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBIFF_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <ModuleDefinitionFile>libiff.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBIFF_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <ModuleDefinitionFile>libiff.def</ModuleDefinitionFile>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="cat.c" />
+    <ClCompile Include="chunk.c" />
+    <ClCompile Include="error.c" />
+    <ClCompile Include="extension.c" />
+    <ClCompile Include="form.c" />
+    <ClCompile Include="group.c" />
+    <ClCompile Include="id.c" />
+    <ClCompile Include="iff.c" />
+    <ClCompile Include="io.c" />
+    <ClCompile Include="list.c" />
+    <ClCompile Include="prop.c" />
+    <ClCompile Include="rawchunk.c" />
+    <ClCompile Include="util.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="cat.h" />
+    <ClInclude Include="chunk.h" />
+    <ClInclude Include="error.h" />
+    <ClInclude Include="extension.h" />
+    <ClInclude Include="form.h" />
+    <ClInclude Include="group.h" />
+    <ClInclude Include="id.h" />
+    <ClInclude Include="iff.h" />
+    <ClInclude Include="ifftypes.h" />
+    <ClInclude Include="io.h" />
+    <ClInclude Include="list.h" />
+    <ClInclude Include="prop.h" />
+    <ClInclude Include="rawchunk.h" />
+    <ClInclude Include="util.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="libiff.def" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 107 - 0
ilbm.mod/libiff/src/libiff/libiff.vcxproj.filters

@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="cat.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="chunk.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="error.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="extension.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="form.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="group.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="id.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="iff.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="io.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="list.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="prop.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="rawchunk.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="util.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="cat.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="chunk.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="error.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="extension.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="form.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="group.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="id.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="iff.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="io.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="list.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="prop.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="rawchunk.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="util.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="ifftypes.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="libiff.def">
+      <Filter>Source Files</Filter>
+    </None>
+  </ItemGroup>
+</Project>

+ 234 - 0
ilbm.mod/libiff/src/libiff/list.c

@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "list.h"
+#include <stdlib.h>
+#include "id.h"
+#include "util.h"
+#include "cat.h"
+#include "error.h"
+
+#define CHUNKID "LIST"
+
+IFF_List *IFF_createList(const char *contentsType)
+{
+    IFF_List *list = (IFF_List*)IFF_allocateChunk(CHUNKID, sizeof(IFF_List));
+    
+    if(list != NULL)
+    {
+	IFF_initGroup((IFF_Group*)list, contentsType);
+	
+	list->prop = NULL;
+	list->propLength = 0;
+    }
+    
+    return list;
+}
+
+void IFF_addPropToList(IFF_List *list, IFF_Prop *prop)
+{
+    list->prop = (IFF_Prop**)realloc(list->prop, (list->propLength + 1) * sizeof(IFF_Prop*));
+    list->prop[list->propLength] = prop;
+    list->propLength++;
+    list->chunkSize = IFF_incrementChunkSize(list->chunkSize, (IFF_Chunk*)prop);
+    
+    prop->parent = (IFF_Group*)list;
+}
+
+void IFF_addToList(IFF_List *list, IFF_Chunk *chunk)
+{
+    IFF_addToCAT((IFF_CAT*)list, chunk);
+}
+
+IFF_List *IFF_readList(FILE *file, const IFF_Long chunkSize, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_ID contentsType;
+    IFF_List *list;
+    
+    /* Read the contentsType id */
+    if(!IFF_readId(file, contentsType, CHUNKID, "contentsType"))
+	return NULL;
+
+    /* Create new list */
+    list = IFF_createList(contentsType);
+    
+    /* Read the remaining nested sub chunks */
+    
+    while(list->chunkSize < chunkSize)
+    {
+	/* Read sub chunk */
+	IFF_Chunk *chunk = IFF_readChunk(file, NULL, extension, extensionLength);
+	
+	if(chunk == NULL)
+	{
+	    IFF_error("Error reading chunk in list!\n");
+	    IFF_freeChunk((IFF_Chunk*)list, NULL, extension, extensionLength);
+	    return NULL;
+	}
+	
+	/* Add the prop or chunk */
+	if(IFF_compareId(chunk->chunkId, "PROP") == 0)
+	    IFF_addPropToList(list, (IFF_Prop*)chunk);
+	else
+	    IFF_addToList(list, chunk);
+    }
+    
+    /* Set the chunk size to what we have read */
+    list->chunkSize = chunkSize;
+    
+    /* Return the resulting list */
+    return list;
+}
+
+int IFF_writeList(FILE *file, const IFF_List *list, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    unsigned int i;
+    
+    if(!IFF_writeId(file, list->contentsType, CHUNKID, "contentsType"))
+    {
+	IFF_error("Error writing contentsType!\n");
+	return FALSE;
+    }
+    
+    for(i = 0; i < list->propLength; i++)
+    {
+	if(!IFF_writeChunk(file, (IFF_Chunk*)list->prop[i], NULL, extension, extensionLength))
+	{
+	    IFF_error("Error writing PROP!\n");
+	    return FALSE;
+	}
+    }
+    
+    if(!IFF_writeGroupSubChunks(file, (IFF_Group*)list, NULL, extension, extensionLength))
+	return FALSE;
+	
+    return TRUE;
+}
+
+int IFF_checkList(const IFF_List *list, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    unsigned int i;
+    IFF_Long chunkSize = IFF_ID_SIZE;
+    IFF_Long subChunkSize;
+    
+    if(!IFF_checkId(list->contentsType))
+	return FALSE;
+
+    /* Check validity of PROP chunks */
+    
+    for(i = 0; i < list->propLength; i++)
+    {
+	IFF_Chunk *propChunk = (IFF_Chunk*)list->prop[i];
+	
+	if(!IFF_checkChunk(propChunk, NULL, extension, extensionLength))
+	    return FALSE;
+	
+	chunkSize = IFF_incrementChunkSize(chunkSize, propChunk);
+    }
+    
+    /* Check validity of other sub chunks */
+    if((subChunkSize = IFF_checkGroupSubChunks((IFF_Group*)list, &IFF_checkCATSubChunk, NULL, extension, extensionLength)) == -1)
+	return FALSE;
+    
+    chunkSize += subChunkSize;
+    
+    /* Check whether the calculated chunk size matches the chunks' chunk size */
+    if(!IFF_checkGroupChunkSize((IFF_Group*)list, chunkSize))
+	return FALSE;
+    
+    return TRUE;
+}
+
+void IFF_freeList(IFF_List *list, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    unsigned int i;
+    
+    IFF_freeCAT((IFF_CAT*)list, extension, extensionLength);
+    
+    for(i = 0; i < list->propLength; i++)
+	IFF_freeChunk((IFF_Chunk*)list->prop[i], NULL, extension, extensionLength);
+
+    free(list->prop);
+}
+
+void IFF_printList(const IFF_List *list, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    unsigned int i;
+    
+    IFF_printGroupType("contentsType", list->contentsType, indentLevel);
+    
+    IFF_printIndent(stdout, indentLevel, "prop = [\n");
+    
+    /* Print shared properties */
+    for(i = 0; i < list->propLength; i++)
+	IFF_printChunk((IFF_Chunk*)list->prop[i], indentLevel + 1, NULL, extension, extensionLength);
+    
+    IFF_printIndent(stdout, indentLevel, "];\n");
+    
+    /* Print sub chunks */
+    IFF_printGroupSubChunks((const IFF_Group *)list, indentLevel, NULL, extension, extensionLength);
+}
+
+int IFF_compareList(const IFF_List *list1, const IFF_List *list2, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    if(list1->propLength == list2->propLength)
+    {
+	unsigned int i;
+	
+	for(i = 0; i < list1->propLength; i++)
+	{
+	    if(!IFF_compareProp(list1->prop[i], list2->prop[i], extension, extensionLength))
+		return FALSE;
+	}
+	
+	return IFF_compareCAT((const IFF_CAT*)list1, (const IFF_CAT*)list2, extension, extensionLength);
+    }
+    else
+	return FALSE;
+}
+
+IFF_Form **IFF_searchFormsInList(IFF_List *list, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength)
+{
+    return IFF_searchFormsInCAT((IFF_CAT*)list, formTypes, formTypesLength, formsLength);
+}
+
+void IFF_updateListChunkSizes(IFF_List *list)
+{
+    unsigned int i;
+    
+    IFF_updateCATChunkSizes((IFF_CAT*)list);
+    
+    for(i = 0; i < list->propLength; i++)
+	list->chunkSize = IFF_incrementChunkSize(list->chunkSize, (IFF_Chunk*)list->prop[i]);
+}
+
+IFF_Prop *IFF_getPropFromList(const IFF_List *list, const char *formType)
+{
+    unsigned int i;
+    
+    for(i = 0; i < list->propLength; i++)
+    {
+	if(IFF_compareId(list->prop[i]->formType, formType) == 0)
+	    return list->prop[i];
+    }
+    
+    return NULL;
+}

+ 192 - 0
ilbm.mod/libiff/src/libiff/list.h

@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_LIST_H
+#define __IFF_LIST_H
+
+typedef struct IFF_List IFF_List;
+
+#include <stdio.h>
+#include "ifftypes.h"
+#include "chunk.h"
+#include "prop.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief A special group chunk, which contains one or more FORM, LIST or CAT chunks and PROP chunks which share common data chunks with the nested group chunks.
+ */
+struct IFF_List
+{
+    /** Pointer to the parent group chunk, in which this chunk is located. The parent points to NULL if there is no parent. */
+    IFF_Group *parent;
+    
+    /** Contains the ID of this chunk, which equals to 'LIST' */
+    IFF_ID chunkId;
+    
+    /** Contains the size of the chunk data in bytes */
+    IFF_Long chunkSize;
+    
+    /**
+     * Contains a type ID which hints about the contents of this list.
+     * 'JJJJ' is used if this concatenation stores forms of multiple form types.
+     * If only one form type is used in this concatenation, this contents type
+     * should be equal to that form type.
+     */
+    IFF_ID contentsType;
+    
+    /** Contains the number of sub chunks stored in this list chunk */
+    unsigned int chunkLength;
+    
+    /** An array of chunk pointers referring to the sub chunks */
+    IFF_Chunk **chunk;
+
+    /** Contains the number of PROP chunks stored in this list chunk */
+    unsigned int propLength;
+    
+    /** An array of chunk pointers referring to the PROP chunks */
+    IFF_Prop **prop;
+};
+
+/**
+ * Creates a new list chunk instance with the given contents type.
+ * The resulting chunk must be freed by using IFF_free().
+ *
+ * @param contentsType Contents type hinting what the contents of the list is.
+ * @return A list chunk or NULL, if the memory for the struct can't be allocated
+ */
+IFF_List *IFF_createList(const char *contentsType);
+
+/**
+ * Adds a PROP chunk to the body of the given list. This function also increments the
+ * chunk size and PROP length counter.
+ *
+ * @param list An instance of a list struct
+ * @param prop A PROP chunk
+ */
+void IFF_addPropToList(IFF_List *list, IFF_Prop *prop);
+
+/**
+ * Adds a chunk to the body of the given list. This function also increments the
+ * chunk size and chunk length counter.
+ *
+ * @param list An instance of a list struct
+ * @param chunk A FORM, CAT or LIST chunk
+ */
+void IFF_addToList(IFF_List *list, IFF_Chunk *chunk);
+
+/**
+ * Reads a list chunk and its sub chunks from a file. The resulting chunk must be
+ * freed by using IFF_free().
+ *
+ * @param file File descriptor of the file
+ * @param chunkSize Size of the chunk data
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return The list struct derived from the file, or NULL if an error has occured
+ */
+IFF_List *IFF_readList(FILE *file, const IFF_Long chunkSize, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes a list chunk and its sub chunks to a file.
+ *
+ * @param file File descriptor of the file
+ * @param list An instance of a list chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the list has been successfully written, else FALSE
+ */
+int IFF_writeList(FILE *file, const IFF_List *list, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the list chunk and its sub chunks conform to the IFF specification.
+ *
+ * @param list An instance of a list chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the list is valid, else FALSE.
+ */
+int IFF_checkList(const IFF_List *list, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Recursively frees the memory of the sub chunks and PROP chunks of the given list chunk.
+ *
+ * @param list An instance of a list chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_freeList(IFF_List *list, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Displays a textual representation of the list chunk and its sub chunks on the standard output.
+ *
+ * @param list An instance of a list chunk
+ * @param indentLevel Indent level of the textual representation
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_printList(const IFF_List *list, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the given lists' contents is equal to each other.
+ *
+ * @param list1 List to compare
+ * @param list2 List to compare
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the given concatenations are equal, else FALSE
+ */
+int IFF_compareList(const IFF_List *list1, const IFF_List *list2, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Returns an array of form structs of the given form types, which are recursively retrieved from the given list.
+ *
+ * @param list An instance of a list chunk
+ * @param formTypes An array of 4 character form type IDs
+ * @param formTypesLength Length of the form types array
+ * @param formsLength Returns the length of the resulting array
+ * @return An array of form structs
+ */
+IFF_Form **IFF_searchFormsInList(IFF_List *list, const char **formTypes, const unsigned int formTypesLength, unsigned int *formsLength);
+
+/**
+ * Recalculates the chunk size of the given list chunk.
+ *
+ * @param list An instance of a list chunk
+ */
+void IFF_updateListChunkSizes(IFF_List *list);
+
+/**
+ * Retrieves a PROP chunk with the given form type from a list.
+ *
+ * @param list An instance of a list chunk
+ * @param formType Form type describing the purpose of the sub chunks.
+ * @return The requested PROP chunk, or NULL if the PROP chunk does not exists.
+ */
+IFF_Prop *IFF_getPropFromList(const IFF_List *list, const char *formType);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 98 - 0
ilbm.mod/libiff/src/libiff/prop.c

@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "prop.h"
+#include <stdlib.h>
+#include <string.h>
+#include "id.h"
+#include "group.h"
+#include "util.h"
+#include "error.h"
+
+#define PROP_CHUNKID "PROP"
+#define PROP_GROUPTYPENAME "formType"
+
+IFF_Prop *IFF_createProp(const char *formType)
+{
+    return (IFF_Prop*)IFF_createGroup(PROP_CHUNKID, formType);
+}
+
+void IFF_addToProp(IFF_Prop *prop, IFF_Chunk *chunk)
+{
+    IFF_addToForm((IFF_Form*)prop, chunk);
+}
+
+IFF_Prop *IFF_readProp(io_context *context, const IFF_Long chunkSize, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return (IFF_Prop*)IFF_readGroup(context, PROP_CHUNKID, chunkSize, PROP_GROUPTYPENAME, TRUE, extension, extensionLength);
+}
+
+int IFF_writeProp(FILE *file, const IFF_Prop *prop, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_writeForm(file, (IFF_Form*)prop, extension, extensionLength);
+}
+
+static int subChunkCheck(const IFF_Group *group, const IFF_Chunk *subChunk)
+{
+    if(IFF_compareId(subChunk->chunkId, "FORM") == 0 ||
+       IFF_compareId(subChunk->chunkId, "LIST") == 0 ||
+       IFF_compareId(subChunk->chunkId, "CAT ") == 0 ||
+       IFF_compareId(subChunk->chunkId, "PROP") == 0)
+    {
+	IFF_error("ERROR: Element with chunk Id: '");
+	IFF_errorId(subChunk->chunkId);
+	IFF_error("' not allowed in PROP chunk!\n");
+
+	return FALSE;
+    }
+    else
+	return TRUE;
+}
+
+int IFF_checkProp(const IFF_Prop *prop, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_checkGroup((IFF_Group*)prop, &IFF_checkFormType, &subChunkCheck, prop->formType, extension, extensionLength);
+}
+
+void IFF_freeProp(IFF_Prop *prop, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_freeForm((IFF_Form*)prop, extension, extensionLength);
+}
+
+void IFF_printProp(const IFF_Prop *prop, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    IFF_printForm((const IFF_Form *)prop, indentLevel, extension, extensionLength);
+}
+
+int IFF_compareProp(const IFF_Prop *prop1, const IFF_Prop *prop2, const IFF_Extension *extension, const unsigned int extensionLength)
+{
+    return IFF_compareForm((const IFF_Form*)prop1, (const IFF_Form*)prop2, extension, extensionLength);
+}
+
+void IFF_updatePropChunkSizes(IFF_Prop *prop)
+{
+    IFF_updateFormChunkSizes((IFF_Form*)prop);
+}
+
+IFF_Chunk *IFF_getChunkFromProp(const IFF_Prop *prop, const char *chunkId)
+{
+    return IFF_getDataChunkFromForm((IFF_Form*)prop, chunkId);
+}

+ 137 - 0
ilbm.mod/libiff/src/libiff/prop.h

@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_PROP_H
+#define __IFF_PROP_H
+
+typedef struct IFF_Form IFF_Prop;
+
+#include <stdio.h>
+#include "ifftypes.h"
+#include "chunk.h"
+#include "form.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Creates a new PROP chunk instance with the given form type.
+ * The resulting chunk must be freed by using IFF_free().
+ *
+ * @param formType Form type describing the purpose of the sub chunks.
+ * @return FORM chunk or NULL, if the memory for the struct can't be allocated
+ */
+IFF_Prop *IFF_createProp(const char *formType);
+
+/**
+ * Adds a chunk to the body of the given PROP. This function also increments the
+ * chunk size and chunk length counter.
+ *
+ * @param prop An instance of a PROP chunk
+ * @param chunk A data chunk
+ */
+void IFF_addToProp(IFF_Prop *prop, IFF_Chunk *chunk);
+
+/**
+ * Reads a PROP chunk and its sub chunks from a file. The resulting chunk must be
+ * freed by using IFF_free().
+ *
+ * @param file File descriptor of the file
+ * @param chunkSize Size of the chunk data
+ * @param extension Extension array which specifies how application file format chunks can be handled
+ * @param extensionLength Length of the extension array
+ * @return The PROP struct derived from the file, or NULL if an error has occured
+ */
+IFF_Prop *IFF_readProp(io_context *context, const IFF_Long chunkSize, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Writes a PROP chunk and its sub chunks to a file.
+ *
+ * @param file File descriptor of the file
+ * @param prop An instance of a PROP chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the PROP has been successfully written, else FALSE
+ */
+int IFF_writeProp(FILE *file, const IFF_Prop *prop, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the PROP chunk and its sub chunks conform to the IFF specification.
+ *
+ * @param prop An instance of a PROP chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the PROP is valid, else FALSE.
+ */
+int IFF_checkProp(const IFF_Prop *prop, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Recursively frees the memory of the sub chunks of the given PROP chunk.
+ *
+ * @param prop An instance of a PROP chunk
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_freeProp(IFF_Prop *prop, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Displays a textual representation of the PROP chunk and its sub chunks on the standard output.
+ *
+ * @param prop An instance of a PROP chunk
+ * @param indentLevel Indent level of the textual representation
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ */
+void IFF_printProp(const IFF_Prop *prop, const unsigned int indentLevel, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Checks whether the given PROP chunks' contents is equal to each other.
+ *
+ * @param prop1 PROP chunk to compare
+ * @param prop2 PROP chunk to compare
+ * @param extension Extension array which specifies how application file format chunks should be handled
+ * @param extensionLength Length of the extension array
+ * @return TRUE if the given forms are equal, else FALSE
+ */
+int IFF_compareProp(const IFF_Prop *prop1, const IFF_Prop *prop2, const IFF_Extension *extension, const unsigned int extensionLength);
+
+/**
+ * Recalculates the chunk size of the given PROP chunk.
+ *
+ * @param prop An instance of a PROP chunk
+ */
+void IFF_updatePropChunkSizes(IFF_Prop *prop);
+
+/**
+ * Retrieves the chunk with the given chunk ID from the given PROP chunk. 
+ *
+ * @param prop An instance of a PROP chunk
+ * @param chunkId An arbitrary chunk ID
+ * @return The chunk with the given chunk ID, or NULL if the chunk can't be found
+ */
+IFF_Chunk *IFF_getChunkFromProp(const IFF_Prop *prop, const char *chunkId);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 165 - 0
ilbm.mod/libiff/src/libiff/rawchunk.c

@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "rawchunk.h"
+#include <stdlib.h>
+#include <string.h>
+#include "error.h"
+#include "io.h"
+#include "id.h"
+#include "util.h"
+
+IFF_RawChunk *IFF_createRawChunk(const char *chunkId)
+{
+    IFF_RawChunk *rawChunk = (IFF_RawChunk*)IFF_allocateChunk(chunkId, sizeof(IFF_RawChunk));
+    
+    if(rawChunk != NULL)
+	rawChunk->chunkData = NULL;
+    
+    return rawChunk;
+}
+
+void IFF_setRawChunkData(IFF_RawChunk *rawChunk, IFF_UByte *chunkData, IFF_Long chunkSize)
+{
+    rawChunk->chunkData = chunkData;
+    rawChunk->chunkSize = chunkSize;
+}
+
+void IFF_setTextData(IFF_RawChunk *rawChunk, const char *text)
+{
+    size_t textLength = strlen(text);
+    IFF_UByte *chunkData = (IFF_UByte*)malloc(textLength * sizeof(IFF_UByte));
+    
+    memcpy(chunkData, text, textLength);
+    IFF_setRawChunkData(rawChunk, chunkData, textLength);
+}
+
+IFF_RawChunk *IFF_readRawChunk(io_context *context, const char *chunkId, const IFF_Long chunkSize)
+{
+    IFF_RawChunk *rawChunk = IFF_createRawChunk(chunkId);
+    IFF_UByte *chunkData = (IFF_UByte*)malloc(chunkSize * sizeof(IFF_UByte));
+
+    if (chunkData == NULL) {
+        return NULL;
+    }
+	
+    /* Read remaining bytes verbatim */
+	
+    if((context->io.read)(context->userData,chunkData, sizeof(IFF_UByte) * chunkSize) < chunkSize)
+    {
+	IFF_error("Error reading raw chunk body of chunk: '");
+	IFF_errorId(chunkId);
+	IFF_error("'\n");
+	IFF_freeChunk((IFF_Chunk*)rawChunk, NULL, NULL, 0);
+	return NULL;
+    }
+	    
+    /* If the chunk size is odd, we have to read the padding byte */
+    if(!IFF_readPaddingByte(context, chunkSize, chunkId))
+    {
+	IFF_freeChunk((IFF_Chunk*)rawChunk, NULL, NULL, 0);
+	return NULL;
+    }
+    
+    /* Add data to the created chunk */
+    IFF_setRawChunkData(rawChunk, chunkData, chunkSize);
+    
+    /* Return the resulting raw chunk */
+    return rawChunk;
+}
+
+int IFF_writeRawChunk(FILE *file, const IFF_RawChunk *rawChunk)
+{
+    if(fwrite(rawChunk->chunkData, sizeof(IFF_UByte), rawChunk->chunkSize, file) < rawChunk->chunkSize)
+    {
+	IFF_error("Error writing raw chunk body of chunk '");
+	IFF_errorId(rawChunk->chunkId);
+	IFF_error("'\n");
+	return FALSE;
+    }
+	
+    /* If the chunk size is odd, we have to write the padding byte */
+    if(!IFF_writePaddingByte(file, rawChunk->chunkSize, rawChunk->chunkId))
+	return FALSE;
+    
+    return TRUE;
+}
+
+void IFF_freeRawChunk(IFF_RawChunk *rawChunk)
+{
+    free(rawChunk->chunkData);
+}
+
+void IFF_printText(const IFF_RawChunk *rawChunk, const unsigned int indentLevel)
+{
+    unsigned int i;
+	
+    IFF_printIndent(stdout, indentLevel, "text = '\n");
+    IFF_printIndent(stdout, indentLevel + 1, "");
+	
+    for(i = 0; i < rawChunk->chunkSize; i++)
+        printf("%c", rawChunk->chunkData[i]);
+
+    printf("\n");
+    IFF_printIndent(stdout, indentLevel, "';\n");
+}
+
+void IFF_printRaw(const IFF_RawChunk *rawChunk, const unsigned int indentLevel)
+{
+    unsigned int i;
+    IFF_UByte byte;
+	
+    IFF_printIndent(stdout, indentLevel, "bytes = \n");
+    IFF_printIndent(stdout, indentLevel + 1, "");
+	
+    for(i = 0; i < rawChunk->chunkSize; i++)
+    {
+	if(i > 0 && i % 10 == 0)
+	{
+	    printf("\n");
+	    IFF_printIndent(stdout, indentLevel + 1, "");
+	}
+	    
+	byte = rawChunk->chunkData[i];
+	    
+	/* Print extra 0 for small numbers */
+	if(byte <= 0xf)
+	    printf("0");
+	    
+	printf("%x ", byte);
+    }
+	
+    printf("\n");
+    IFF_printIndent(stdout, indentLevel, ";\n");
+}
+
+void IFF_printRawChunk(const IFF_RawChunk *rawChunk, unsigned int indentLevel)
+{
+    if(IFF_compareId(rawChunk->chunkId, "TEXT") == 0)
+	IFF_printText(rawChunk, indentLevel);
+    else
+	IFF_printRaw(rawChunk, indentLevel);
+}
+
+int IFF_compareRawChunk(const IFF_RawChunk *rawChunk1, const IFF_RawChunk *rawChunk2)
+{
+    return (memcmp(rawChunk1->chunkData, rawChunk2->chunkData, rawChunk1->chunkSize) == 0);
+}

+ 142 - 0
ilbm.mod/libiff/src/libiff/rawchunk.h

@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_RAWCHUNK_H
+#define __IFF_RAWCHUNK_H
+
+typedef struct IFF_RawChunk IFF_RawChunk;
+
+#include <stdio.h>
+#include "ifftypes.h"
+#include "chunk.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief A raw chunk, which contains an arbitrary number of bytes.
+ */
+struct IFF_RawChunk
+{
+    /** Pointer to the parent group chunk, in which this chunk is located. The parent points to NULL if there is no parent. */
+    IFF_Group *parent;
+    
+    /** Contains a 4 character ID of this chunk */
+    IFF_ID chunkId;
+    
+    /** Contains the size of the chunk data in bytes */
+    IFF_Long chunkSize;
+    
+    /** An array of bytes representing raw chunk data */
+    IFF_UByte *chunkData;
+};
+
+/**
+ * Creates a raw chunk with the given chunk ID. The resulting chunk must be freed using IFF_free().
+ * 
+ * @param chunkId A 4 character id
+ * @return A raw chunk with the given chunk Id, or NULL if the memory can't be allocated
+ */
+IFF_RawChunk *IFF_createRawChunk(const char *chunkId);
+
+/**
+ * Attaches chunk data to a given chunk. It also increments the chunk size.
+ *
+ * @param rawChunk A raw chunk
+ * @param chunkData An array of bytes
+ * @param chunkSize Length of the bytes array.
+ */
+void IFF_setRawChunkData(IFF_RawChunk *rawChunk, IFF_UByte *chunkData, IFF_Long chunkSize);
+
+/**
+ * Copies the given string into the data of the chunk. Additionally, it makes
+ * the chunk size equal to the given string.
+ *
+ * @param rawChunk A raw chunk
+ * @param text Text to store in the body
+ */
+void IFF_setTextData(IFF_RawChunk *rawChunk, const char *text);
+
+/**
+ * Reads a raw chunk with the given chunk id and chunk size from a file. The resulting chunk must be freed using IFF_free().
+ *
+ * @param file File descriptor of the file
+ * @param chunkId A 4 character chunk id
+ * @param chunkSize Size of the chunk data
+ * @return The raw chunk struct derived from the file, or NULL if an error has occured
+ */
+IFF_RawChunk *IFF_readRawChunk(io_context *context, const char *chunkId, const IFF_Long chunkSize);
+
+/**
+ * Writes the given raw chunk to a file descriptor.
+ *
+ * @param file File descriptor of the file
+ * @param rawChunk A raw chunk instance
+ * @return TRUE if the chunk has been successfully written, else FALSE
+ */
+int IFF_writeRawChunk(FILE *file, const IFF_RawChunk *rawChunk);
+
+/**
+ * Frees the raw chunk data of the given raw chunk.
+ *
+ * @param rawChunk A raw chunk instance
+ */
+void IFF_freeRawChunk(IFF_RawChunk *rawChunk);
+
+/**
+ * Prints the data of the raw chunk as text
+ *
+ * @param rawChunk A raw chunk instance
+ * @param indentLevel Indent level of the textual representation
+ */
+void IFF_printText(const IFF_RawChunk *rawChunk, const unsigned int indentLevel);
+
+/**
+ * Prints the data of the raw chunk as numeric values
+ *
+ * @param rawChunk A raw chunk instance
+ * @param indentLevel Indent level of the textual representation
+ */
+void IFF_printRaw(const IFF_RawChunk *rawChunk, const unsigned int indentLevel);
+
+/**
+ * Displays a textual representation of the raw chunk data on the standard output.
+ *
+ * @param rawChunk A raw chunk instance
+ * @param indentLevel Indent level of the textual representation
+ */
+void IFF_printRawChunk(const IFF_RawChunk *rawChunk, unsigned int indentLevel);
+
+/**
+ * Checks whether two given raw chunks are equal.
+ *
+ * @param rawChunk1 Raw chunk to compare
+ * @param rawChunk2 Raw chunk to compare
+ * @return TRUE if the raw chunks are equal, else FALSE
+ */
+int IFF_compareRawChunk(const IFF_RawChunk *rawChunk1, const IFF_RawChunk *rawChunk2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 37 - 0
ilbm.mod/libiff/src/libiff/util.c

@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "util.h"
+#include <stdarg.h>
+
+void IFF_printIndent(FILE *file, const unsigned int indentLevel, const char *formatString, ...)
+{
+    va_list ap;
+    unsigned int i;
+    
+    va_start(ap, formatString);
+    
+    for(i = 0; i < indentLevel; i++)
+      fprintf(file, "  ");
+    
+    vfprintf(file, formatString, ap);
+    va_end(ap);
+}

+ 46 - 0
ilbm.mod/libiff/src/libiff/util.h

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __IFF_UTIL_H
+#define __IFF_UTIL_H
+
+#include <stdio.h>
+#include "ifftypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Prints a formatted string to the given file descriptor using a certain indent
+ * level.
+ *
+ * @param file File descriptor of the file
+ * @param indentLevel Indent level
+ * @param formatString A format specifier for fprintf()
+ */
+void IFF_printIndent(FILE *file, const unsigned int indentLevel, const char *formatString, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 123 - 0
ilbm.mod/libiff/tests/Makefile.am

@@ -0,0 +1,123 @@
+noinst_HEADERS = bye.h hello.h test.h catdata.h formdata.h listdata.h formdata-pad.h nestedformdata.h extensiondata.h
+
+check_PROGRAMS = writeform readform writeform-pad readform-pad writenestedform readnestedform writecat readcat writelist readlist invalidiff validiff \
+    searchforms-form searchforms-cat searchforms-nestedform updatechunksizes lookupproperty-simple lookupproperty-prop lookupproperty-override lookupproperty-nested \
+    writeextension readextension checkextension ppextension
+
+writeform_SOURCES = formdata.c writeform.c
+writeform_LDADD = ../src/libiff/libiff.la
+writeform_CFLAGS = -I../src/libiff
+
+readform_SOURCES = formdata.c readform.c
+readform_LDADD = ../src/libiff/libiff.la
+readform_CFLAGS = -I../src/libiff
+
+writeform_pad_SOURCES = formdata-pad.c writeform-pad.c
+writeform_pad_LDADD = ../src/libiff/libiff.la
+writeform_pad_CFLAGS = -I../src/libiff
+
+readform_pad_SOURCES = formdata-pad.c readform-pad.c
+readform_pad_LDADD = ../src/libiff/libiff.la
+readform_pad_CFLAGS = -I../src/libiff
+
+writenestedform_SOURCES = nestedformdata.c writenestedform.c
+writenestedform_LDADD = ../src/libiff/libiff.la
+writenestedform_CFLAGS = -I../src/libiff
+
+readnestedform_SOURCES = nestedformdata.c readnestedform.c
+readnestedform_LDADD = ../src/libiff/libiff.la
+readnestedform_CFLAGS = -I../src/libiff
+
+writecat_SOURCES = catdata.c writecat.c
+writecat_LDADD = ../src/libiff/libiff.la
+writecat_CFLAGS = -I../src/libiff
+
+readcat_SOURCES = catdata.c readcat.c
+readcat_LDADD = ../src/libiff/libiff.la
+readcat_CFLAGS = -I../src/libiff
+
+writelist_SOURCES = listdata.c writelist.c
+writelist_LDADD = ../src/libiff/libiff.la
+writelist_CFLAGS = -I../src/libiff
+
+readlist_SOURCES = listdata.c readlist.c
+readlist_LDADD = ../src/libiff/libiff.la
+readlist_CFLAGS = -I../src/libiff
+
+validiff_SOURCES = validiff.c
+validiff_LDADD = ../src/libiff/libiff.la
+validiff_CFLAGS = -I../src/libiff
+
+invalidiff_SOURCES = invalidiff.c
+invalidiff_LDADD = ../src/libiff/libiff.la
+invalidiff_CFLAGS = -I../src/libiff
+
+lookupproperty_simple_SOURCES = lookupproperty-simple.c
+lookupproperty_simple_LDADD = ../src/libiff/libiff.la
+lookupproperty_simple_CFLAGS  = -I../src/libiff
+
+lookupproperty_prop_SOURCES = lookupproperty-prop.c
+lookupproperty_prop_LDADD = ../src/libiff/libiff.la
+lookupproperty_prop_CFLAGS  = -I../src/libiff
+
+lookupproperty_override_SOURCES = lookupproperty-override.c
+lookupproperty_override_LDADD = ../src/libiff/libiff.la
+lookupproperty_override_CFLAGS  = -I../src/libiff
+
+lookupproperty_nested_SOURCES = lookupproperty-nested.c
+lookupproperty_nested_LDADD = ../src/libiff/libiff.la
+lookupproperty_nested_CFLAGS  = -I../src/libiff
+
+searchforms_form_SOURCES = searchforms-form.c
+searchforms_form_LDADD = ../src/libiff/libiff.la
+searchforms_form_CFLAGS = -I../src/libiff
+
+searchforms_cat_SOURCES = searchforms-cat.c
+searchforms_cat_LDADD = ../src/libiff/libiff.la
+searchforms_cat_CFLAGS = -I../src/libiff
+
+searchforms_nestedform_SOURCES = searchforms-nestedform.c
+searchforms_nestedform_LDADD = ../src/libiff/libiff.la
+searchforms_nestedform_CFLAGS = -I../src/libiff
+
+updatechunksizes_SOURCES = updatechunksizes.c
+updatechunksizes_LDADD = ../src/libiff/libiff.la
+updatechunksizes_CFLAGS = -I../src/libiff
+
+writeextension_SOURCES = hello.c bye.c test.c extensiondata.c writeextension.c
+writeextension_LDADD = ../src/libiff/libiff.la
+writeextension_CFLAGS = -I../src/libiff
+
+readextension_SOURCES = hello.c bye.c test.c extensiondata.c readextension.c
+readextension_LDADD = ../src/libiff/libiff.la
+readextension_CFLAGS = -I../src/libiff
+
+checkextension_SOURCES = hello.c bye.c test.c checkextension.c
+checkextension_LDADD = ../src/libiff/libiff.la
+checkextension_CFLAGS = -I../src/libiff
+
+ppextension_SOURCES = hello.c bye.c test.c ppextension.c
+ppextension_LDADD = ../src/libiff/libiff.la
+ppextension_CFLAGS = -I../src/libiff
+
+TESTS = writeform readform writeform-pad readform-pad writenestedform readnestedform writecat readcat writelist readlist \
+    validform.sh validcat.sh validcat-wildcard.sh validlist.sh validlist-wildcard.sh invalidiff.sh \
+    invalidid1.sh invalidid2.sh invalidformtype1.sh invalidformtype2.sh invalidformtype3.sh invalidformtype4.sh \
+    invalidform-prop.sh invalidform-size1.sh invalidform-size2.sh \
+    invalidcat-raw.sh invalidcat-prop.sh invalidcat-contentstype.sh invalidcat-size.sh \
+    invalidlist-raw.sh invalidlist-contentstype.sh invalidlist-size.sh \
+    invalidprop.sh invalidprop-size.sh invalidlist-negsize.sh \
+    pp-text.sh searchforms-form searchforms-cat searchforms-nestedform updatechunksizes \
+    lookupproperty-simple lookupproperty-prop lookupproperty-override lookupproperty-nested \
+    join-identical.sh join-different.sh \
+    writeextension readextension checkextension ppextension-c.sh ppextension-otherform.sh
+
+EXTRA_DIST = invalidcat-contentstype.sh invalidcat-prop.sh invalidcat-raw.sh invalidcat-size.sh invalidform-prop.sh invalidform-size1.sh \
+    invalidform-size2.sh invalidformtype1.sh invalidformtype2.sh invalidformtype3.sh invalidformtype4.sh invalidid1.sh invalidid2.sh \
+    invalidiff.sh invalidlist-contentstype.sh invalidlist-raw.sh invalidlist-size.sh invalidprop.sh invalidprop-size.sh join-different.sh \
+    join-identical.sh ppextension-c.sh ppextension-otherform.sh pp-text.sh validcat.sh validcat-wildcard.sh validform.sh validlist.sh validlist-wildcard.sh \
+    extension-otherform.TEST invalidcat-contentstype.TEST invalidcat-prop.TEST invalidcat-raw.TEST invalidcat-size.TEST invalidform-prop.TEST \
+    invalidform-size1.TEST invalidform-size2.TEST invalidformtype1.TEST invalidformtype2.TEST invalidformtype3.TEST invalidformtype4.TEST \
+    invalidid1.TEST invalidid2.TEST invalidlist-contentstype.TEST invalidlist-raw.TEST invalidlist-size.TEST invalidprop-size.TEST invalidprop.TEST \
+    lookupproperty-nested.TEST lookupproperty-override.TEST pp-text.TEST validcat-wildcard.TEST validlist-wildcard.TEST \
+    join.HELO join.BYE invalidlist-negsize.sh invalidlist-negsize.TEST

+ 105 - 0
ilbm.mod/libiff/tests/bye.c

@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "bye.h"
+#include <stdlib.h>
+#include <io.h>
+#include <error.h>
+#include <util.h>
+#include "test.h"
+
+#define CHUNKID "BYE "
+
+TEST_Bye *TEST_createBye(void)
+{
+    TEST_Bye *bye = (TEST_Bye*)IFF_allocateChunk(CHUNKID, sizeof(TEST_Bye));
+    
+    if(bye != NULL)
+	bye->chunkSize = 2 * sizeof(IFF_Long);
+    
+    return bye;
+}
+
+IFF_Chunk *TEST_readBye(FILE *file, const IFF_Long chunkSize)
+{
+    TEST_Bye *bye = TEST_createBye();
+    
+    if(bye != NULL)
+    {
+	if(!IFF_readLong(file, &bye->one, CHUNKID, "one"))
+	{
+	    TEST_free((IFF_Chunk*)bye);
+	    return NULL;
+	}
+    
+	if(!IFF_readLong(file, &bye->two, CHUNKID, "two"))
+	{
+	    TEST_free((IFF_Chunk*)bye);
+	    return NULL;
+	}
+    }
+    
+    return (IFF_Chunk*)bye;
+}
+
+int TEST_writeBye(FILE *file, const IFF_Chunk *chunk)
+{
+    const TEST_Bye *bye = (const TEST_Bye*)chunk;
+    
+    if(!IFF_writeLong(file, bye->one, CHUNKID, "one"))
+	return FALSE;
+    
+    if(!IFF_writeLong(file, bye->two, CHUNKID, "two"))
+	return FALSE;
+    
+    return TRUE;
+}
+
+int TEST_checkBye(const IFF_Chunk *chunk)
+{
+    return TRUE;
+}
+
+void TEST_freeBye(IFF_Chunk *chunk)
+{
+}
+
+void TEST_printBye(const IFF_Chunk *chunk, const unsigned int indentLevel)
+{
+    const TEST_Bye *bye = (const TEST_Bye*)chunk;
+    
+    IFF_printIndent(stdout, indentLevel, "one = %d;\n", bye->one);
+    IFF_printIndent(stdout, indentLevel, "two = %d;\n", bye->two);
+}
+
+int TEST_compareBye(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2)
+{
+    const TEST_Bye *bye1 = (const TEST_Bye*)chunk1;
+    const TEST_Bye *bye2 = (const TEST_Bye*)chunk2;
+
+    if(bye1->one != bye2->one)
+	return FALSE;
+
+    if(bye1->two != bye2->two)
+	return FALSE;
+
+    return TRUE;
+}

+ 55 - 0
ilbm.mod/libiff/tests/bye.h

@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __TEST_BYE_H
+#define __TEST_BYE_H
+
+#include <ifftypes.h>
+#include <chunk.h>
+#include <stdio.h>
+
+typedef struct
+{
+    IFF_Group *parent;
+    
+    IFF_ID chunkId;
+    IFF_Long chunkSize;
+    
+    IFF_Long one;
+    IFF_Long two;
+}
+TEST_Bye;
+
+TEST_Bye *TEST_createBye(void);
+
+IFF_Chunk *TEST_readBye(FILE *file, const IFF_Long chunkSize);
+
+int TEST_writeBye(FILE *file, const IFF_Chunk *chunk);
+
+int TEST_checkBye(const IFF_Chunk *chunk);
+
+void TEST_freeBye(IFF_Chunk *chunk);
+
+void TEST_printBye(const IFF_Chunk *chunk, const unsigned int indentLevel);
+
+int TEST_compareBye(const IFF_Chunk *chunk1, const IFF_Chunk *chunk2);
+
+#endif

+ 82 - 0
ilbm.mod/libiff/tests/catdata.c

@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "catdata.h"
+#include <stdlib.h>
+#include <string.h>
+#include <form.h>
+#include <rawchunk.h>
+
+#define HELO_1_BYTES_SIZE 4
+#define BYE_1_BYTES_SIZE 3
+#define HELO_2_BYTES_SIZE 5
+#define BYE_2_BYTES_SIZE 4
+
+IFF_UByte helo1Data[] = {'a', 'b', 'c', 'd'};
+IFF_UByte bye1Data[] = {'E', 'F', 'G'};
+IFF_UByte helo2Data[] = {'a', 'b', 'c', 'd', 'e'};
+IFF_UByte bye2Data[] = {'F', 'G', 'H', 'I'};
+
+IFF_CAT *IFF_createTestCAT()
+{
+    IFF_Form *test1Form, *test2Form;
+    IFF_CAT *cat;
+    IFF_RawChunk *helo1Chunk, *helo2Chunk, *bye1Chunk, *bye2Chunk;
+    IFF_UByte *helo1Bytes, *helo2Bytes, *bye1Bytes, *bye2Bytes;
+    
+    helo1Bytes = (IFF_UByte*)malloc(HELO_1_BYTES_SIZE * sizeof(IFF_UByte));
+    memcpy(helo1Bytes, helo1Data, HELO_1_BYTES_SIZE);
+    
+    helo1Chunk = IFF_createRawChunk("HELO");
+    IFF_setRawChunkData(helo1Chunk, helo1Bytes, HELO_1_BYTES_SIZE);
+    
+    bye1Bytes = (IFF_UByte*)malloc(BYE_1_BYTES_SIZE * sizeof(IFF_UByte));
+    memcpy(bye1Bytes, bye1Data, BYE_1_BYTES_SIZE);
+    
+    bye1Chunk = IFF_createRawChunk("BYE ");
+    IFF_setRawChunkData(bye1Chunk, bye1Bytes, BYE_1_BYTES_SIZE);
+    
+    test1Form = IFF_createForm("TEST");
+    IFF_addToForm(test1Form, (IFF_Chunk*)helo1Chunk);
+    IFF_addToForm(test1Form, (IFF_Chunk*)bye1Chunk);
+    
+    helo2Bytes = (IFF_UByte*)malloc(HELO_2_BYTES_SIZE * sizeof(IFF_UByte));
+    memcpy(helo2Bytes, helo2Data, HELO_2_BYTES_SIZE);
+    
+    helo2Chunk = IFF_createRawChunk("HELO");
+    IFF_setRawChunkData(helo2Chunk, helo2Bytes, HELO_2_BYTES_SIZE);
+    
+    bye2Bytes = (IFF_UByte*)malloc(BYE_2_BYTES_SIZE * sizeof(IFF_UByte));
+    memcpy(bye2Bytes, bye2Data, BYE_2_BYTES_SIZE);
+    
+    bye2Chunk = IFF_createRawChunk("BYE ");
+    IFF_setRawChunkData(bye2Chunk, bye2Bytes, BYE_2_BYTES_SIZE);
+    
+    test2Form = IFF_createForm("TEST");
+    IFF_addToForm(test2Form, (IFF_Chunk*)helo2Chunk);
+    IFF_addToForm(test2Form, (IFF_Chunk*)bye2Chunk);
+    
+    cat = IFF_createCAT("TEST");
+    IFF_addToCAT(cat, (IFF_Chunk*)test1Form);
+    IFF_addToCAT(cat, (IFF_Chunk*)test2Form);
+    
+    return cat;
+}

+ 29 - 0
ilbm.mod/libiff/tests/catdata.h

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2012 Sander van der Burg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so, 
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __CATDATA_H
+#define __CATDATA_H
+
+#include <cat.h>
+
+IFF_CAT *IFF_createTestCAT(void);
+
+#endif

Some files were not shown because too many files changed in this diff