Index: /oup/releases/0.23a/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.23a/OniUnPacker.bdsproj	(revision 23)
+++ /oup/releases/0.23a/OniUnPacker.bdsproj	(revision 23)
@@ -0,0 +1,172 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<PersonalityInfo>
+		<Option>
+			<Option Name="Personality">Delphi.Personality</Option>
+			<Option Name="ProjectType"></Option>
+			<Option Name="Version">1.0</Option>
+			<Option Name="GUID">{5F594E8D-8185-4AC6-8191-2A0F26194CB4}</Option>
+		</Option>
+	</PersonalityInfo>
+	<Delphi.Personality>
+		<Source>
+			<Source Name="MainSource">OniUnPacker.dpr</Source>
+		</Source>
+		<FileVersion>
+			<FileVersion Name="Version">7.0</FileVersion>
+		</FileVersion>
+		<Compiler>
+			<Compiler Name="A">8</Compiler>
+			<Compiler Name="B">0</Compiler>
+			<Compiler Name="C">1</Compiler>
+			<Compiler Name="D">1</Compiler>
+			<Compiler Name="E">0</Compiler>
+			<Compiler Name="F">0</Compiler>
+			<Compiler Name="G">1</Compiler>
+			<Compiler Name="H">1</Compiler>
+			<Compiler Name="I">1</Compiler>
+			<Compiler Name="J">0</Compiler>
+			<Compiler Name="K">0</Compiler>
+			<Compiler Name="L">1</Compiler>
+			<Compiler Name="M">0</Compiler>
+			<Compiler Name="N">1</Compiler>
+			<Compiler Name="O">1</Compiler>
+			<Compiler Name="P">1</Compiler>
+			<Compiler Name="Q">0</Compiler>
+			<Compiler Name="R">0</Compiler>
+			<Compiler Name="S">0</Compiler>
+			<Compiler Name="T">0</Compiler>
+			<Compiler Name="U">0</Compiler>
+			<Compiler Name="V">1</Compiler>
+			<Compiler Name="W">0</Compiler>
+			<Compiler Name="X">1</Compiler>
+			<Compiler Name="Y">1</Compiler>
+			<Compiler Name="Z">1</Compiler>
+			<Compiler Name="ShowHints">True</Compiler>
+			<Compiler Name="ShowWarnings">True</Compiler>
+			<Compiler Name="UnitAliases">WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;</Compiler>
+			<Compiler Name="NamespacePrefix"></Compiler>
+			<Compiler Name="GenerateDocumentation">False</Compiler>
+			<Compiler Name="DefaultNamespace"></Compiler>
+			<Compiler Name="SymbolDeprecated">True</Compiler>
+			<Compiler Name="SymbolLibrary">True</Compiler>
+			<Compiler Name="SymbolPlatform">True</Compiler>
+			<Compiler Name="SymbolExperimental">True</Compiler>
+			<Compiler Name="UnitLibrary">True</Compiler>
+			<Compiler Name="UnitPlatform">True</Compiler>
+			<Compiler Name="UnitDeprecated">True</Compiler>
+			<Compiler Name="UnitExperimental">True</Compiler>
+			<Compiler Name="HResultCompat">True</Compiler>
+			<Compiler Name="HidingMember">True</Compiler>
+			<Compiler Name="HiddenVirtual">True</Compiler>
+			<Compiler Name="Garbage">True</Compiler>
+			<Compiler Name="BoundsError">True</Compiler>
+			<Compiler Name="ZeroNilCompat">True</Compiler>
+			<Compiler Name="StringConstTruncated">True</Compiler>
+			<Compiler Name="ForLoopVarVarPar">True</Compiler>
+			<Compiler Name="TypedConstVarPar">True</Compiler>
+			<Compiler Name="AsgToTypedConst">True</Compiler>
+			<Compiler Name="CaseLabelRange">True</Compiler>
+			<Compiler Name="ForVariable">True</Compiler>
+			<Compiler Name="ConstructingAbstract">True</Compiler>
+			<Compiler Name="ComparisonFalse">True</Compiler>
+			<Compiler Name="ComparisonTrue">True</Compiler>
+			<Compiler Name="ComparingSignedUnsigned">True</Compiler>
+			<Compiler Name="CombiningSignedUnsigned">True</Compiler>
+			<Compiler Name="UnsupportedConstruct">True</Compiler>
+			<Compiler Name="FileOpen">True</Compiler>
+			<Compiler Name="FileOpenUnitSrc">True</Compiler>
+			<Compiler Name="BadGlobalSymbol">True</Compiler>
+			<Compiler Name="DuplicateConstructorDestructor">True</Compiler>
+			<Compiler Name="InvalidDirective">True</Compiler>
+			<Compiler Name="PackageNoLink">True</Compiler>
+			<Compiler Name="PackageThreadVar">True</Compiler>
+			<Compiler Name="ImplicitImport">True</Compiler>
+			<Compiler Name="HPPEMITIgnored">True</Compiler>
+			<Compiler Name="NoRetVal">True</Compiler>
+			<Compiler Name="UseBeforeDef">True</Compiler>
+			<Compiler Name="ForLoopVarUndef">True</Compiler>
+			<Compiler Name="UnitNameMismatch">True</Compiler>
+			<Compiler Name="NoCFGFileFound">True</Compiler>
+			<Compiler Name="MessageDirective">True</Compiler>
+			<Compiler Name="ImplicitVariants">True</Compiler>
+			<Compiler Name="UnicodeToLocale">True</Compiler>
+			<Compiler Name="LocaleToUnicode">True</Compiler>
+			<Compiler Name="ImagebaseMultiple">True</Compiler>
+			<Compiler Name="SuspiciousTypecast">True</Compiler>
+			<Compiler Name="PrivatePropAccessor">True</Compiler>
+			<Compiler Name="UnsafeType">False</Compiler>
+			<Compiler Name="UnsafeCode">False</Compiler>
+			<Compiler Name="UnsafeCast">False</Compiler>
+			<Compiler Name="OptionTruncated">True</Compiler>
+			<Compiler Name="WideCharReduced">True</Compiler>
+			<Compiler Name="DuplicatesIgnored">True</Compiler>
+		</Compiler>
+		<Linker>
+			<Linker Name="MapFile">0</Linker>
+			<Linker Name="OutputObjs">0</Linker>
+			<Linker Name="ConsoleApp">1</Linker>
+			<Linker Name="DebugInfo">False</Linker>
+			<Linker Name="RemoteSymbols">False</Linker>
+			<Linker Name="GenerateDRC">False</Linker>
+			<Linker Name="MinStackSize">16384</Linker>
+			<Linker Name="MaxStackSize">1048576</Linker>
+			<Linker Name="ImageBase">4194304</Linker>
+			<Linker Name="ExeDescription"></Linker>
+		</Linker>
+		<Directories>
+			<Directories Name="OutputDir"></Directories>
+			<Directories Name="UnitOutputDir"></Directories>
+			<Directories Name="PackageDLLOutputDir"></Directories>
+			<Directories Name="PackageDCPOutputDir"></Directories>
+			<Directories Name="SearchPath"></Directories>
+			<Directories Name="Packages">xmlrtl;rtl;vcl;vclie;inet;inetdbbde;inetdbxpress;vclx;IndySystem;IndyCore;dbrtl;dsnap;soaprtl;IndyProtocols;bdertl;vcldbx;vcldb;webdsnap;websnap;vclactnband;GridPackd2005;TWrapGrid;Package1;A406_R70;CoolTrayIcon_D6plus</Directories>
+			<Directories Name="Conditionals"></Directories>
+			<Directories Name="DebugSourceDirs"></Directories>
+			<Directories Name="UsePackages">False</Directories>
+		</Directories>
+		<Parameters>
+			<Parameters Name="RunParams"></Parameters>
+			<Parameters Name="HostApplication"></Parameters>
+			<Parameters Name="Launcher"></Parameters>
+			<Parameters Name="UseLauncher">False</Parameters>
+			<Parameters Name="DebugCWD"></Parameters>
+			<Parameters Name="RemoteHost"></Parameters>
+			<Parameters Name="RemotePath"></Parameters>
+			<Parameters Name="RemoteLauncher"></Parameters>
+			<Parameters Name="RemoteCWD"></Parameters>
+			<Parameters Name="RemoteDebug">False</Parameters>
+		</Parameters>
+		<VersionInfo>
+			<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+			<VersionInfo Name="AutoIncBuild">False</VersionInfo>
+			<VersionInfo Name="MajorVer">1</VersionInfo>
+			<VersionInfo Name="MinorVer">0</VersionInfo>
+			<VersionInfo Name="Release">0</VersionInfo>
+			<VersionInfo Name="Build">0</VersionInfo>
+			<VersionInfo Name="Debug">False</VersionInfo>
+			<VersionInfo Name="PreRelease">False</VersionInfo>
+			<VersionInfo Name="Special">False</VersionInfo>
+			<VersionInfo Name="Private">False</VersionInfo>
+			<VersionInfo Name="DLL">False</VersionInfo>
+			<VersionInfo Name="Locale">1031</VersionInfo>
+			<VersionInfo Name="CodePage">1252</VersionInfo>
+		</VersionInfo>
+		<VersionInfoKeys>
+			<VersionInfoKeys Name="CompanyName"></VersionInfoKeys>
+			<VersionInfoKeys Name="FileDescription"></VersionInfoKeys>
+			<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+			<VersionInfoKeys Name="InternalName"></VersionInfoKeys>
+			<VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys>
+			<VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys>
+			<VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys>
+			<VersionInfoKeys Name="ProductName"></VersionInfoKeys>
+			<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+			<VersionInfoKeys Name="Comments"></VersionInfoKeys>
+		</VersionInfoKeys>  
+    <Excluded_Packages>
+      <Excluded_Packages Name="C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Bpl\TCrossEdit.bpl">(untitled)</Excluded_Packages>
+      <Excluded_Packages Name="d:\programme\borland\bds\3.0\Bin\dbwebxprt.bpl">Borland Web Wizard Package</Excluded_Packages>
+    </Excluded_Packages>
+  </Delphi.Personality>
+</BorlandProject>
Index: /oup/releases/0.23a/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.23a/OniUnPacker.cfg	(revision 23)
+++ /oup/releases/0.23a/OniUnPacker.cfg	(revision 23)
@@ -0,0 +1,38 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J-
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q-
+-$R-
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$YD
+-$Z1
+-cg
+-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+-H+
+-W+
+-M
+-$M16384,1048576
+-K$00400000
+-LE"C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Bpl"
+-LN"C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Bpl"
+-w-UNSAFE_TYPE
+-w-UNSAFE_CODE
+-w-UNSAFE_CAST
Index: /oup/releases/0.23a/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.23a/OniUnPacker.dpr	(revision 23)
+++ /oup/releases/0.23a/OniUnPacker.dpr	(revision 23)
@@ -0,0 +1,26 @@
+PROGRAM OniUnPacker;
+uses
+  Forms,
+  Unit1_main in 'Unit1_main.pas' {Form1},
+  Unit2_functions in 'Unit2_functions.pas',
+  Unit3_data in 'Unit3_data.pas',
+  Unit4_Exporters in 'Unit4_Exporters.pas',
+  Unit5_preview in 'Unit5_preview.pas' {Form5},
+  Unit6_imgfuncs in 'Unit6_imgfuncs.pas',
+  Unit7_txmpreplace in 'Unit7_txmpreplace.pas' {Form7},
+  Unit8_binedit in 'Unit8_binedit.pas' {Form8},
+  Unit9_data_structures in 'Unit9_data_structures.pas',
+  Unit10_leveldb in 'Unit10_leveldb.pas' {Form10},
+  Unit11_extractor in 'Unit11_extractor.pas' {Form11},
+  Unit12_ValueEdit in 'Unit12_ValueEdit.pas' {Form12};
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.CreateForm(TForm12, Form12);
+  Application.Run;
+END.
Index: /oup/releases/0.23a/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.23a/Unit10_leveldb.dfm	(revision 23)
+++ /oup/releases/0.23a/Unit10_leveldb.dfm	(revision 23)
@@ -0,0 +1,61 @@
+object Form10: TForm10
+  Left = 0
+  Top = 0
+  BorderStyle = bsNone
+  Caption = 'Creating DB'
+  ClientHeight = 90
+  ClientWidth = 401
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poScreenCenter
+  PixelsPerInch = 96
+  TextHeight = 13
+  object group_progress: TGroupBox
+    Left = 0
+    Top = 0
+    Width = 400
+    Height = 89
+    Caption = 'Progress ...'
+    TabOrder = 0
+    object lbl_progress: TLabel
+      Left = 2
+      Top = 32
+      Width = 396
+      Height = 17
+      Align = alTop
+      AutoSize = False
+    end
+    object lbl_estimation: TLabel
+      Left = 2
+      Top = 49
+      Width = 396
+      Height = 17
+      Align = alTop
+      AutoSize = False
+      Caption = 'Estimated finishing time:'
+    end
+    object progress: TProgressBar
+      Left = 2
+      Top = 15
+      Width = 396
+      Height = 17
+      Align = alTop
+      Smooth = True
+      TabOrder = 0
+    end
+    object btn_abortok: TButton
+      Left = 3
+      Top = 64
+      Width = 60
+      Height = 22
+      Caption = 'Abort...'
+      TabOrder = 1
+      OnClick = btn_abortokClick
+    end
+  end
+end
Index: /oup/releases/0.23a/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.23a/Unit10_leveldb.pas	(revision 23)
+++ /oup/releases/0.23a/Unit10_leveldb.pas	(revision 23)
@@ -0,0 +1,1092 @@
+UNIT Unit10_leveldb;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ComCtrls, StdCtrls, StrUtils;
+
+TYPE
+  TForm10 = Class(TForm)
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    btn_abortok: TButton;
+    lbl_estimation: TLabel;
+    PROCEDURE btn_abortokClick(Sender: TObject);
+  PRIVATE
+    PROCEDURE HandleFile(ext:String; fileid:LongWord; dir_dat2db:Boolean);
+    PROCEDURE stop_convert;
+  PUBLIC
+    PROCEDURE CreateDatabase(FileName:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data;
+TYPE
+  THandler=PROCEDURE(fileid:LongWord; dir_dat2db:Boolean);
+  TConvertHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+VAR
+  ConvertHandlers:Array OF TConvertHandlers;
+  loaded_filename:String;
+  converting:Boolean=False;
+  abort:Boolean=False;
+  filestream:TFileStream;
+  dat_stream:TMemoryStream;
+  mem:TMemoryStream;
+  DataBase:TABSDatabase;
+  Query:TABSQuery;
+  MimeCoder: TStringFormat_MIME64;
+
+PROCEDURE TForm10.HandleFile;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO Length(ConvertHandlers) DO
+      IF UpperCase(ConvertHandlers[i].Ext)=UpperCase(ext) THEN
+        IF ConvertHandlers[i].needed THEN BEGIN
+          ConvertHandlers[i].Handler(fileid, dir_dat2db);
+          Break;
+        END ELSE
+          Break;
+  END;
+
+PROCEDURE TForm10.CreateDatabase(FileName:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+  CONST
+    steps:Byte=4;
+  PROCEDURE DoStep(stepname:String);
+    BEGIN
+      Inc(step);
+      IF stepname<>'FIN' THEN
+        group_progress.Caption:='Creating DB (Step '+IntToStr(step)+'/'+IntToStr(steps)+': '+stepname+')'
+      ELSE
+        group_progress.Caption:='Creating DB (FINISHED)';
+    END;
+  BEGIN
+    Form10.Visible:=True;
+    Form1.Visible:=False;
+    step:=0;
+    converting:=True;
+    abort:=False;
+    loaded_filename:=FileName;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=FileName;
+    DataBase.CreateDatabase;
+
+    DoStep('Creating tables');
+    progress.Position:=0;
+    lbl_progress.Caption:='';
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+    Application.ProcessMessages;
+
+    Query:=TABSQuery.Create(Self);
+    Query.DatabaseName:='OLDB';
+    Query.SQL.Text:='CREATE TABLE globals  ( id AUTOINC PRIMARY KEY, name STRING(128), value STRING(128) );';
+    Query.ExecSQL;
+    Query.SQL.Text:='CREATE TABLE linkmap  ( id AUTOINC PRIMARY KEY, src_id INTEGER, src_link_offset INTEGER, target_id INTEGER );';
+    Query.ExecSQL;
+    Query.SQL.Text:='CREATE TABLE rawmap  ( id AUTOINC PRIMARY KEY, src_id INTEGER, src_link_offset INTEGER, size INTEGER, data BLOB BlobCompressionMode 9 BlobBlockSize 1024 BlobCompressionAlgorithm ZLib );';
+//    Query.SQL.Text:='CREATE TABLE rawmap  ( id AUTOINC PRIMARY KEY, src_id INTEGER, src_link_offset INTEGER, size INTEGER, data BLOB BlobCompressionAlgorithm None );';
+    Query.ExecSQL;
+    Query.SQL.Text:='CREATE TABLE datfiles  ( id INTEGER PRIMARY KEY, extension CHAR(4), name STRING(128), contenttype INTEGER, size INTEGER, data BLOB BlobCompressionMode 9 BlobBlockSize 1024 BlobCompressionAlgorithm ZLib );';
+//    Query.SQL.Text:='CREATE TABLE datfiles  ( id INTEGER PRIMARY KEY, extension CHAR(4), name STRING(128), contenttype INTEGER, size INTEGER, data BLOB BlobCompressionAlgorithm None );';
+    Query.ExecSQL;
+    Query.SQL.Text:='CREATE TABLE extlist  ( id AUTOINC PRIMARY KEY, ext CHAR(4), ident CHAR(16) );';
+    Query.ExecSQL;
+
+    Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("dbversion","'+dbversion+'");';
+    Query.ExecSQL;
+    SetLength(data,Length(dat_header.Ident));
+    FOR i:=0 TO High(dat_header.Ident) DO data[i]:=dat_header.Ident[i];
+    temps:=CreateHexString(data,True);
+    Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("ident","'+temps+'");';
+    Query.ExecSQL;
+    data:=LoadDatFile(0);
+    i:=data[7];
+    i:=i DIV 2;
+    Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("lvl","'+IntToStr(i)+'");';
+    Query.ExecSQL;
+
+    DoStep('Writing extensionslist');
+    progress.Max:=dat_header.Extensions;
+    Application.ProcessMessages;
+
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      SetLength(data,Length(dat_extensionsmap[i].Ident));
+      FOR j:=0 TO High(dat_extensionsmap[i].Ident) DO data[j]:=dat_extensionsmap[i].Ident[j];
+      temps:=CreateHexString(data,True);
+      temps2:=dat_extensionsmap[i].Extension[3]+dat_extensionsmap[i].Extension[2]+dat_extensionsmap[i].Extension[1]+dat_extensionsmap[i].Extension[0];
+      Query.SQL.Text:='INSERT INTO extlist (ext,ident) VALUES ("'+temps2+'","'+temps+'");';
+      Query.ExecSQL;
+      progress.Position:=i;
+      lbl_progress.Caption:='Extensions done: '+IntToStr(i)+'/'+IntToStr(dat_header.Extensions);
+      Application.ProcessMessages;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    lbl_progress.Caption:='';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    filestream:=TFileStream.Create(dat_filename, fmOpenRead);
+    dat_stream:=TMemoryStream.Create;
+    dat_stream.CopyFrom(filestream,0);
+    dat_stream.Seek(0,soFromBeginning);
+    filestream.Free;
+
+    progress.Max:=dat_header.Files;
+    begintime:=Time;
+    DoStep('Writing .dat-fileslist');
+    Application.ProcessMessages;
+
+    Database.StartTransaction;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].FileType AND $02)=0 THEN BEGIN
+        dat_stream.Seek(dat_files[i].DatAddr,soFromBeginning);
+        mimecoder:=TStringFormat_MIME64.Create;
+        mem:=TMemoryStream.Create;
+        mem.CopyFrom(dat_stream,dat_files[i].Size);
+        Query.SQL.Text:='INSERT INTO datfiles (id,extension,name,contenttype,size,data) VALUES ('+IntToStr(i)+',"'+dat_files[i].Extension+'","'+dat_files[i].Name+'","'+IntToHex(dat_files[i].FileType,8)+'",'+IntToStr(dat_files[i].size)+',MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") );';
+        Query.ExecSQL;
+        mem.Free;
+        mimecoder.Free;
+        HandleFile(dat_files[i].Extension,i,True);
+      END ELSE BEGIN
+        Query.SQL.Text:='INSERT INTO datfiles (id,extension,name,contenttype,size) VALUES ('+IntToStr(i)+',"'+dat_files[i].Extension+'","'+dat_files[i].Name+'","'+IntToHex(dat_files[i].FileType,8)+'",0);';
+        Query.ExecSQL;
+      END;
+      IF ( (i MOD 100)=0 ) AND (i>0) THEN BEGIN
+        Database.Commit(False);
+        Database.StartTransaction;
+      END;
+      IF ( (i MOD 25)=0 ) AND (i>=100) THEN
+        lbl_estimation.Caption:='Estimated finishing time: '+TimeToStr((Time-begintime)/i*dat_header.Files+begintime);
+      progress.Position:=i;
+      lbl_progress.Caption:='Files done: '+IntToStr(i)+'/'+IntToStr(dat_header.Files);
+      Application.ProcessMessages;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    Database.Commit(False);
+    progress.Position:=dat_header.Files;
+    lbl_progress.Caption:='Files done: '+IntToStr(dat_header.Files)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='FINISHED (duration: '+TimeToStr(Time-absolutebegintime)+')';
+
+    DoStep('FIN');
+    btn_abortok.Caption:='&OK';
+    btn_abortok.Default:=True;
+
+    loaded_filename:='';
+    converting:=False;
+    dat_stream.Free;
+
+    database.Close;
+    database.Free;
+  END;
+
+PROCEDURE TForm10.stop_convert;
+  BEGIN
+    btn_abortok.Caption:='&Close';
+    btn_abortok.Default:=True;
+    converting:=False;
+    lbl_estimation.Caption:='ABORTED';
+    group_progress.Caption:='Creating DB (ABORTED)';
+    DataBase.Close;
+    IF MessageBox(Self.Handle, PChar('Delete the unfinished DB-file?'), PChar('Delete file?'), MB_YESNO)=IDYES THEN BEGIN
+      DeleteFile(loaded_filename);
+    END;
+  END;
+
+PROCEDURE TForm10.btn_abortokClick(Sender: TObject);
+  BEGIN
+    IF converting THEN BEGIN
+      IF MessageBox(Self.Handle, PChar('Do you really want to cancel the convert-progress?'), PChar('Warning: Converting'), MB_YESNO)=IDYES THEN
+        abort:=True;
+    END ELSE BEGIN
+      Form10.Visible:=False;
+      Form1.Visible:=True;
+    END;
+  END;
+
+
+PROCEDURE LoadFilePart(fileid,offset,size:LongWord; target:Pointer);
+  BEGIN
+    dat_stream.Seek(dat_files[fileid].DatAddr+offset,soFromBeginning);
+    dat_stream.Read(target^,size);
+  END;
+
+PROCEDURE InsertDatLinkToDB(fileid:LongWord; offset:LongWord);
+  VAR
+    link:LongWord;
+  BEGIN
+    LoadFilePart(fileid,offset,4,@link);
+    IF link=0 THEN
+      link:=$FFFFFFFF
+    ELSE
+      link:=link DIV 256;
+    Query.SQL.Text:='INSERT INTO linkmap (src_id,src_link_offset,target_id) VALUES ('+IntToStr(fileid)+','+IntToStr(offset)+','+IntToStr(link)+');';
+    Query.ExecSQL;
+  END;
+
+PROCEDURE InsertRawFileToDB(fileid:LongWord; src_offset,raw_addr,size:LongWord);
+  VAR
+    localmem:TMemoryStream;
+//    temps:String;
+  BEGIN
+    IF size>0 THEN BEGIN
+      localmem:=TMemoryStream.Create;
+      filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+      filestream.Seek(raw_addr,soFromBeginning);
+      localmem.CopyFrom(filestream,size);
+      filestream.Free;
+      mimecoder:=TStringFormat_MIME64.Create;
+      Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(fileid)+','+IntToStr(src_offset)+','+IntToStr(size)+',MimeToBin("'+MimeCoder.StrTo(localmem.Memory, localmem.Size)+'") );';
+      Query.ExecSQL;
+      localmem.Free;
+      mimecoder.Free;
+    END ELSE BEGIN
+      Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(fileid)+','+IntToStr(src_offset)+',0);';
+      Query.ExecSQL;
+    END;
+{    IF (raw_addr MOD 32)>0 THEN BEGIN
+      temps:='FileID='+FormatNumber(fileid,5,'0')+' - dat-Offset=0x'+IntToHex(src_offset,8)+' - raw-address=0x'+IntToHex(raw_addr,8)+#13+#10;
+      filestream:=TFileStream.Create('D:\not32.txt',fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd);
+      filestream.Write(temps[1],Length(temps));
+      filestream.Free;
+    END; }
+  END;
+
+
+
+PROCEDURE AGDB(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      FOR i:=0 TO links-1 DO BEGIN
+        LoadFilePart(fileid,$20+i*4,4,@link);
+        InsertRawFileToDB(fileid,$20+i*4,link,1(*????????????????????????????????*));
+      END;
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE AKEV(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 16 DO InsertDatLinkToDB(fileid,$8+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE AKOT(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 4 DO InsertDatLinkToDB(fileid,$8+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE BINA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$0C,4,@link);
+      LoadFilePart(fileid,$08,4,@datasize);
+      InsertRawFileToDB(fileid,$0C,link,datasize);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE CBPI(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 56 DO InsertDatLinkToDB(fileid,$8+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE CBPM(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 18 DO InsertDatLinkToDB(fileid,$8+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE CONS(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 1 DO InsertDatLinkToDB(fileid,$24+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE CRSA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$14,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*1100+$A0);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE DOOR(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$08);
+      InsertDatLinkToDB(fileid,$10);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE DPGE(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE HPGE(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$0C);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE IGHH(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$24);
+      InsertDatLinkToDB(fileid,$28);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE IGPA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@links);
+      IF links>0 THEN
+        FOR i:=0 TO links-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE IGPG(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 1 DO InsertDatLinkToDB(fileid,$1C+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE IGSA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@links);
+      IF links>0 THEN
+        FOR i:=0 TO links-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE IMPT(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$10);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE IPGE(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$0C);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE KEYI(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 9 DO InsertDatLinkToDB(fileid,$08+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE M3GA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@links);
+      IF links>0 THEN
+        FOR i:=0 TO links-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE M3GM(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 6 DO InsertDatLinkToDB(fileid,$0C+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE MTRL(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$10);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE OBOA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:Word;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*240);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE OFGA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*12+$04);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE ONCC(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE ONCV(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$08);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE ONLV(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 5 DO InsertDatLinkToDB(fileid,$48+i*4);
+      FOR i:=0 TO 5 DO InsertDatLinkToDB(fileid,$64+i*4);
+      InsertDatLinkToDB(fileid,$300);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE ONOA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*8+$04);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE ONSK(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$08);
+      InsertDatLinkToDB(fileid,$0C);
+      InsertDatLinkToDB(fileid,$10);
+      InsertDatLinkToDB(fileid,$14);
+      InsertDatLinkToDB(fileid,$18);
+      InsertDatLinkToDB(fileid,$20);
+      InsertDatLinkToDB(fileid,$44);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE ONVL(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE ONWC(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$28);
+      InsertDatLinkToDB(fileid,$34);
+      InsertDatLinkToDB(fileid,$54);
+      InsertDatLinkToDB(fileid,$58);
+      InsertDatLinkToDB(fileid,$5C);
+      InsertDatLinkToDB(fileid,$60);
+      InsertDatLinkToDB(fileid,$6FC);
+      InsertDatLinkToDB(fileid,$700);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE OPGE(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$1C);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE OSBD(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$08,4,@datasize);
+      LoadFilePart(fileid,$0C,4,@link);
+      InsertRawFileToDB(fileid,$0C,link,datasize);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE PSPC(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$50);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE PSPL(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$24+i*8);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE PSUI(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 43 DO InsertDatLinkToDB(fileid,$08+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE SNDD(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$40,4,@datasize);
+      LoadFilePart(fileid,$44,4,@link);
+      InsertRawFileToDB(fileid,$44,link,datasize);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE SUBT(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    baselink,link:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+    filestream:TFileStream;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$18,4,@baselink);
+      LoadFilePart(fileid,$1C,4,@links);
+      IF links>0 THEN BEGIN
+        FOR i:=0 TO links-1 DO BEGIN
+          LoadFilePart(fileid,$20+i*4,4,@link);
+          SetLength(data,1024);
+          filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+          filestream.Seek(baselink+link,soFromBeginning);
+          filestream.Read(data[0],1024);
+          filestream.Free;
+          k:=0;
+          FOR j:=0 TO 1024 DO BEGIN
+            IF (data[j]=$00) OR (j=1024) THEN BEGIN
+              IF j<1024 THEN BEGIN
+                IF k=0 THEN BEGIN
+                  k:=1;
+                END ELSE BEGIN
+                  InsertRawFileToDB(fileid,$20+i*4,baselink+link,j);
+                  Break;
+                END;
+              END ELSE
+                ShowMessage('Error: Didn''t find message-end-marker...');
+            END;
+          END;
+        END;
+      END;
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE STNA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:Word;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRAC(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:Word;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$18);
+      LoadFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*12+8);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRAM(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$16C,2,@frames);
+      {y-pos}
+      LoadFilePart(fileid,$0C,4,@link);
+      InsertRawFileToDB(fileid,$0C,link,frames*4);
+      {x-z-pos}
+      LoadFilePart(fileid,$10,4,@link);
+      InsertRawFileToDB(fileid,$10,link,frames*8);
+      {attacks}
+      LoadFilePart(fileid,$182,1,@tempb);
+      LoadFilePart(fileid,$14,4,@link);
+      InsertRawFileToDB(fileid,$14,link,tempb*32);
+      {damage}
+      LoadFilePart(fileid,$183,1,@tempb);
+      LoadFilePart(fileid,$18,4,@link);
+      InsertRawFileToDB(fileid,$18,link,tempb*8);
+      {motionblur}
+      LoadFilePart(fileid,$184,1,@tempb);
+      LoadFilePart(fileid,$1C,4,@link);
+      InsertRawFileToDB(fileid,$1C,link,tempb*8);
+      {shortcut}
+      LoadFilePart(fileid,$185,1,@tempb);
+      LoadFilePart(fileid,$20,4,@link);
+      InsertRawFileToDB(fileid,$20,link,tempb*8);
+      {throw}
+      LoadFilePart(fileid,$24,4,@link);
+      InsertRawFileToDB(fileid,$24,link,24);
+      {footstep}
+      LoadFilePart(fileid,$186,1,@tempb);
+      LoadFilePart(fileid,$28,4,@link);
+      InsertRawFileToDB(fileid,$28,link,tempb*4);
+      {particle}
+      LoadFilePart(fileid,$187,1,@tempb);
+      LoadFilePart(fileid,$2C,4,@link);
+      InsertRawFileToDB(fileid,$2C,link,tempb*24);
+      {position}
+      LoadFilePart(fileid,$30,4,@link);
+      InsertRawFileToDB(fileid,$30,link,frames*8);
+      {particle}
+      LoadFilePart(fileid,$154,2,@tempw);
+      LoadFilePart(fileid,$38,4,@link);
+      InsertRawFileToDB(fileid,$38,link,tempw*34);
+      {extent}
+      LoadFilePart(fileid,$138,1,@templ);
+      LoadFilePart(fileid,$13C,4,@link);
+      InsertRawFileToDB(fileid,$13C,link,templ*12);
+
+      LoadFilePart(fileid,$34,4,@link);
+      tempw:=0;
+      IF link>0 THEN BEGIN
+        {BODY ANIMATIONS PART DECODE!!!}
+        SetLength(data,$FFFF);
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+        filestream.Seek(link,soFromBeginning);
+        filestream.Read(data[0],$FFFF);
+        filestream.Free;
+        offset:=data[24]+data[25]*255;
+        {}
+      END;
+      InsertRawFileToDB(fileid,$34,link,tempw);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRAS(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$08);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRBS(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 4 DO InsertDatLinkToDB(fileid,$08+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRCM(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 2 DO InsertDatLinkToDB(fileid,$5C+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRGA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:Word;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRGE(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$20);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRIG(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$18);
+      InsertDatLinkToDB(fileid,$24);
+      InsertDatLinkToDB(fileid,$28);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRMA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:Word;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TRSC(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:Word;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TSFF(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TSFT(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$1C);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TURR(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$60);
+      InsertDatLinkToDB(fileid,$6C);
+      InsertDatLinkToDB(fileid,$74);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TXAN(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TXMA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TXMB(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TXMP(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    link:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$8C,SizeOf(x),@x);
+      LoadFilePart(fileid,$8E,SizeOf(y),@y);
+      LoadFilePart(fileid,$90,SizeOf(storetype),@storetype);
+      LoadFilePart(fileid,$9C,4,@link);
+      CASE storetype OF
+        0,1,2: datasize:=x*y*2;
+        8: datasize:=x*y*4;
+        9: datasize:=x*y DIV 2;
+      END;
+      InsertRawFileToDB(fileid,$9C,link,datasize);
+      InsertDatLinkToDB(fileid,$94);
+      InsertDatLinkToDB(fileid,$98);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE TXTC(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$08);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE WMCL(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$24);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE WMMB(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE WPGE(fileid:LongWord; dir_dat2db:Boolean);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$08);
+      InsertDatLinkToDB(fileid,$0C);
+    END ELSE BEGIN
+    END;
+  END;
+
+PROCEDURE InsertHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(ConvertHandlers,Length(ConvertHandlers)+1);
+    ConvertHandlers[High(ConvertHandlers)].Ext:=ext;
+    ConvertHandlers[High(ConvertHandlers)].needed:=needed;
+    ConvertHandlers[High(ConvertHandlers)].handler:=handler;
+  END;
+
+BEGIN
+  InsertHandler('ABNA',False,NIL);
+//  InsertHandler('AGDB',True,AGDB);
+  InsertHandler('AGDB',False,NIL);
+  InsertHandler('AGQC',False,NIL);
+  InsertHandler('AGQG',False,NIL);
+  InsertHandler('AGQR',False,NIL);
+  InsertHandler('AISA',False,NIL);
+  InsertHandler('AITR',False,NIL);
+  InsertHandler('AKAA',False,NIL);
+  InsertHandler('AKBA',False,NIL);
+  InsertHandler('AKBP',False,NIL);
+  InsertHandler('AKDA',False,NIL);
+  InsertHandler('AKEV',True,AKEV);
+  InsertHandler('AKOT',True,AKOT);
+  InsertHandler('AKVA',False,NIL);
+  InsertHandler('BINA',True,BINA);
+  InsertHandler('CBPI',True,CBPI);
+  InsertHandler('CBPM',True,CBPM);
+  InsertHandler('CONS',True,CONS);
+  InsertHandler('CRSA',True,CRSA);
+  InsertHandler('DOOR',True,DOOR);
+  InsertHandler('DPGE',True,DPGE);
+  InsertHandler('ENVP',False,NIL);
+  InsertHandler('FILM',False,NIL);
+  InsertHandler('HPGE',True,HPGE);
+  InsertHandler('IDXA',False,NIL);
+  InsertHandler('IGHH',True,IGHH);
+  InsertHandler('IGPA',True,IGPA);
+  InsertHandler('IGPG',True,IGPG);
+  InsertHandler('IGSA',True,IGSA);
+  InsertHandler('IMPT',True,IMPT);
+  InsertHandler('IPGE',True,IPGE);
+  InsertHandler('KEYI',True,KEYI);
+  InsertHandler('M3GA',True,M3GA);
+  InsertHandler('M3GM',True,M3GM);
+  InsertHandler('MTRL',True,MTRL);
+  InsertHandler('OBAN',False,NIL);
+  InsertHandler('OBDC',False,NIL);
+  InsertHandler('OBOA',True,OBOA);
+  InsertHandler('OFGA',True,OFGA);
+  InsertHandler('ONCC',True,ONCC);
+  InsertHandler('ONCP',False,NIL);
+  InsertHandler('ONCV',True,ONCV);
+  InsertHandler('ONFA',False,NIL);
+  InsertHandler('ONGS',False,NIL);
+  InsertHandler('ONIA',False,NIL);
+  InsertHandler('ONLD',False,NIL);
+  InsertHandler('ONLV',True,ONLV);
+  InsertHandler('ONMA',False,NIL);
+  InsertHandler('ONOA',True,ONOA);
+  InsertHandler('ONSA',False,NIL);
+  InsertHandler('ONSK',True,ONSK);
+  InsertHandler('ONTA',False,NIL);
+  InsertHandler('ONVL',True,ONVL);
+  InsertHandler('ONWC',True,ONWC);
+  InsertHandler('OPGE',True,OPGE);
+  InsertHandler('OSBD',True,OSBD);
+  InsertHandler('OTIT',False,NIL);
+  InsertHandler('OTLF',False,NIL);
+  InsertHandler('PLEA',False,NIL);
+  InsertHandler('PNTA',False,NIL);
+  InsertHandler('PSPC',True,PSPC);
+  InsertHandler('PSPL',True,PSPL);
+  InsertHandler('PSUI',True,PSUI);
+  InsertHandler('QTNA',False,NIL);
+  InsertHandler('SNDD',True,SNDD);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',True,SUBT);
+  InsertHandler('TRAC',True,TRAC);
+  InsertHandler('TRAM',True,TRAM);
+  InsertHandler('TRAS',True,TRAS);
+  InsertHandler('TRBS',True,TRBS);
+  InsertHandler('TRCM',True,TRCM);
+  InsertHandler('TRGA',True,TRGA);
+  InsertHandler('TRGE',True,TRGE);
+  InsertHandler('TRIA',False,NIL);
+  InsertHandler('TRIG',True,TRIG);
+  InsertHandler('TRMA',True,TRMA);
+  InsertHandler('TRSC',True,TRSC);
+  InsertHandler('TRTA',False,NIL);
+  InsertHandler('TSFF',True,TSFF);
+  InsertHandler('TSFL',False,NIL);
+  InsertHandler('TSFT',True,TSFT);
+  InsertHandler('TSGA',False,NIL);
+  InsertHandler('TSTR',False,NIL);
+  InsertHandler('TURR',True,TURR);
+  InsertHandler('TXAN',True,TXAN);
+  InsertHandler('TXCA',False,NIL);
+  InsertHandler('TXMA',True,TXMA);
+  InsertHandler('TXMB',True,TXMB);
+  InsertHandler('TXMP',True,TXMP);
+  InsertHandler('TXTC',True,TXTC);
+  InsertHandler('VCRA',False,NIL);
+  InsertHandler('WMCL',True,WMCL);
+  InsertHandler('WMDD',False,NIL);
+  InsertHandler('WMM_',False,NIL);
+  InsertHandler('WMMB',True,WMMB);
+  InsertHandler('WPGE',True,WPGE);   
+END.
Index: /oup/releases/0.23a/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.23a/Unit11_extractor.dfm	(revision 23)
+++ /oup/releases/0.23a/Unit11_extractor.dfm	(revision 23)
@@ -0,0 +1,257 @@
+object Form11: TForm11
+  Left = 0
+  Top = 0
+  Width = 495
+  Height = 425
+  Caption = 'Extractor'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object group_select: TGroupBox
+    Left = 0
+    Top = 0
+    Width = 191
+    Height = 398
+    Align = alClient
+    Caption = '1. Select file(s)'
+    TabOrder = 0
+    object panel_extension: TPanel
+      Left = 2
+      Top = 293
+      Width = 187
+      Height = 103
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      OnResize = panel_extensionResize
+      object lbl_filter: TLabel
+        Left = 2
+        Top = 62
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = 'Filter by &extension:'
+        FocusControl = combo_extension
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 76
+        Width = 145
+        Height = 21
+        Style = csDropDownList
+        DropDownCount = 12
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Tahoma'
+        Font.Style = []
+        ItemHeight = 13
+        ParentFont = False
+        Sorted = True
+        TabOrder = 3
+        OnClick = combo_extensionClick
+      end
+      object check_zerobyte: TCheckBox
+        Left = 2
+        Top = 44
+        Width = 130
+        Height = 13
+        Caption = 'Show &zero-byte files'
+        TabOrder = 2
+        OnClick = check_zerobyteClick
+      end
+      object edit_filtername: TEdit
+        Left = 2
+        Top = 20
+        Width = 145
+        Height = 18
+        AutoSize = False
+        TabOrder = 1
+      end
+      object check_filtername: TCheckBox
+        Left = 2
+        Top = 5
+        Width = 130
+        Height = 15
+        Caption = 'Filter by file&name:'
+        TabOrder = 0
+        OnClick = check_filternameClick
+      end
+    end
+    object list: TListBox
+      Left = 2
+      Top = 15
+      Width = 187
+      Height = 278
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 1
+    end
+  end
+  object group_extract: TGroupBox
+    Left = 191
+    Top = 0
+    Width = 296
+    Height = 398
+    Align = alRight
+    Caption = '2. Select extract-method'
+    TabOrder = 1
+    object group_singlefiles: TGroupBox
+      Left = 8
+      Top = 16
+      Width = 281
+      Height = 185
+      Caption = 'Write data into single files'
+      TabOrder = 0
+      object btn_sel_dat: TButton
+        Left = 8
+        Top = 16
+        Width = 129
+        Height = 49
+        Caption = 'Selected files (dat contents only)'
+        TabOrder = 0
+        WordWrap = True
+        OnClick = Extract
+      end
+      object btn_sel_datraw: TButton
+        Left = 8
+        Top = 72
+        Width = 129
+        Height = 49
+        Caption = 'Selected files (dat+raw)'
+        TabOrder = 1
+        WordWrap = True
+        OnClick = Extract
+      end
+      object btn_sel_datraw_convert: TButton
+        Left = 8
+        Top = 128
+        Width = 129
+        Height = 49
+        Caption = 'Selected files (dat+raw) (with convert if possible)'
+        TabOrder = 2
+        WordWrap = True
+        OnClick = Extract
+      end
+      object btn_all_dat: TButton
+        Left = 144
+        Top = 16
+        Width = 129
+        Height = 49
+        Caption = 'All files in list (dat contents only)'
+        TabOrder = 3
+        WordWrap = True
+        OnClick = Extract
+      end
+      object btn_all_datraw: TButton
+        Left = 144
+        Top = 72
+        Width = 129
+        Height = 49
+        Caption = 'All files in list (dat+raw)'
+        TabOrder = 4
+        WordWrap = True
+        OnClick = Extract
+      end
+      object btn_all_datraw_convert: TButton
+        Left = 144
+        Top = 128
+        Width = 129
+        Height = 49
+        BiDiMode = bdLeftToRight
+        Caption = 'All files in list (dat+raw) (with convert if possible)'
+        ParentBiDiMode = False
+        TabOrder = 5
+        WordWrap = True
+        OnClick = Extract
+      end
+    end
+    object group_onefile: TGroupBox
+      Left = 8
+      Top = 208
+      Width = 281
+      Height = 73
+      Caption = 'Write data into one file'
+      TabOrder = 1
+      object btn_sel_files_toone: TButton
+        Left = 8
+        Top = 16
+        Width = 129
+        Height = 49
+        Caption = 'Selected files (dat contents only)'
+        TabOrder = 0
+        WordWrap = True
+        OnClick = Extract
+      end
+      object btn_all_files_toone: TButton
+        Left = 144
+        Top = 16
+        Width = 129
+        Height = 49
+        Caption = 'All files in list (dat contents only)'
+        TabOrder = 1
+        WordWrap = True
+        OnClick = Extract
+      end
+    end
+    object group_progress: TGroupBox
+      Left = 8
+      Top = 288
+      Width = 281
+      Height = 105
+      Caption = 'Progress ...'
+      TabOrder = 2
+      Visible = False
+      object lbl_progress: TLabel
+        Left = 8
+        Top = 40
+        Width = 265
+        Height = 17
+        AutoSize = False
+        Caption = 'Files done: 0/0'
+      end
+      object lbl_estimated: TLabel
+        Left = 8
+        Top = 56
+        Width = 265
+        Height = 17
+        AutoSize = False
+        Caption = 'Estimated finishing time: 00:00:00'
+      end
+      object progress: TProgressBar
+        Left = 8
+        Top = 16
+        Width = 265
+        Height = 17
+        Smooth = True
+        TabOrder = 0
+      end
+      object btn_abort: TButton
+        Left = 8
+        Top = 72
+        Width = 97
+        Height = 23
+        Caption = 'Abort'
+        Enabled = False
+        TabOrder = 1
+      end
+    end
+  end
+  object saved: TSaveDialog
+    Left = 448
+    Top = 328
+  end
+end
Index: /oup/releases/0.23a/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.23a/Unit11_extractor.pas	(revision 23)
+++ /oup/releases/0.23a/Unit11_extractor.pas	(revision 23)
@@ -0,0 +1,242 @@
+UNIT Unit11_extractor;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, ExtCtrls, StrUtils, ComCtrls;
+TYPE
+  TForm11 = Class(TForm)
+    group_select: TGroupBox;
+    group_extract: TGroupBox;
+    group_singlefiles: TGroupBox;
+    btn_sel_dat: TButton;
+    btn_sel_datraw: TButton;
+    btn_sel_datraw_convert: TButton;
+    btn_all_dat: TButton;
+    btn_all_datraw: TButton;
+    btn_all_datraw_convert: TButton;
+    group_onefile: TGroupBox;
+    btn_sel_files_toone: TButton;
+    btn_all_files_toone: TButton;
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    lbl_estimated: TLabel;
+    btn_abort: TButton;
+    saved: TSaveDialog;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    check_zerobyte: TCheckBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    list: TListBox;
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE check_zerobyteClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE FormActivate(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE Extract(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form11: TForm11;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit2_functions, Unit3_data;
+
+
+PROCEDURE TForm11.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=GetExtensionsList;
+    FOR i:=0 TO High(exts) DO
+      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm11.LoadFileNames;
+  VAR
+    Extension:String[4];
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    no_zero_bytes:=NOT check_zerobyte.Checked;
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN Extension:='';
+
+    files:=GetFilesList(extension,pattern,no_zero_bytes);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  END;
+
+PROCEDURE TForm11.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm11.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm11.check_zerobyteClick(Sender: TObject);
+  VAR
+    i:Byte;
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm11.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+
+
+PROCEDURE TForm11.FormResize(Sender: TObject);
+  BEGIN
+    IF Self.Width>=450 THEN BEGIN
+    END ELSE Self.Width:=450;
+    IF Self.Height>=400 THEN BEGIN
+      group_progress.Height:=group_extract.Height-293;
+    END ELSE Self.Height:=400;
+  END;
+
+PROCEDURE TForm11.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm11.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm11.FormCreate(Sender: TObject);
+  BEGIN
+    btn_sel_dat.Caption:=           'Selected files'+CrLf+'(dat contents only)';
+    btn_sel_datraw.Caption:=        'Selected files'+CrLf+'(dat+raw contents)';
+    btn_sel_datraw_convert.Caption:='Selected files'+CrLf+'(dat+raw contents)'+CrLf+'(with convert if possible)';
+    btn_all_dat.Caption:=           'All files in list'+CrLf+'(dat contents only)';
+    btn_all_datraw.Caption:=        'All files in list'+CrLf+'(dat+raw contents)';
+    btn_all_datraw_convert.Caption:='All files in list'+CrLf+'(dat+raw contents)'+CrLf+'(with convert if possible)';
+    btn_sel_files_toone.Caption:=   'Selected files'+CrLf+'(dat contents only)';
+    btn_all_files_toone.Caption:=   'All files in list'+CrLf+'(dat contents only)';
+  END;
+
+PROCEDURE TForm11.Extract(Sender: TObject);
+  VAR
+    sel_only:Boolean;
+    dat_only:Boolean;
+    convert:Boolean;
+    one_file:Boolean;
+    settings:TExportSet;
+    files:LongWord;
+    i,done:LongWord;
+    begintime:Double;
+  BEGIN
+    sel_only:=Pos('sel',TButton(Sender).Name)>0;
+    dat_only:=NOT (Pos('datraw',TButton(Sender).Name)>0);
+    convert:=Pos('convert',TButton(Sender).Name)>0;
+    one_file:=Pos('toone',TButton(Sender).Name)>0;
+    IF dat_only THEN settings:=[DO_dat]
+    ELSE settings:=[DO_dat,DO_raw];
+    IF convert THEN settings:=settings+[DO_convert];
+    IF one_file THEN settings:=settings+[DO_toone];
+    progress.Position:=0;
+
+    IF saved.Execute THEN BEGIN
+      begintime:=Time;
+      group_progress.Visible:=True;
+      group_select.Enabled:=False;
+      group_singlefiles.Enabled:=False;
+      group_onefile.Enabled:=False;
+      lbl_estimated.Caption:='Estimated finishing time: unknown';
+      IF one_file THEN BEGIN
+        IF FileExists(saved.FileName) THEN BEGIN
+          IF MessageBox(Self.Handle,PChar('File already exists. Do you want to overwrite it?'),PChar('Warning!'),MB_YESNO)=ID_YES THEN BEGIN
+            DeleteFile(saved.FileName);
+          END ELSE BEGIN
+            group_progress.Visible:=False;
+            group_select.Enabled:=True;
+            group_singlefiles.Enabled:=True;
+            group_onefile.Enabled:=True;
+            Exit;
+          END;
+        END;
+        i:=FileCreate(saved.FileName);
+        FileClose(i);
+        i:=0;
+      END;
+      IF sel_only THEN BEGIN
+        files:=list.SelCount;
+        lbl_progress.Caption:='Files done: 0/'+IntToStr(files);
+        progress.Max:=files;
+        done:=0;
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF list.Selected[i] THEN BEGIN
+            IF one_file THEN BEGIN
+              ExportFile(StrToInt(MidStr(list.Items.Strings[i],1,5)),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+            END ELSE BEGIN
+              ExportFile(StrToInt(MidStr(list.Items.Strings[i],1,5)),list.Items.Strings[i],settings,'D:');
+            END;
+            Inc(done);
+          END;
+          IF ((done MOD 10)=0) AND (done>=50) THEN
+            lbl_estimated.Caption:='Estimated finishing time: '+TimeToStr((Time-begintime)/done*files+begintime);
+          IF (i MOD 10)=0 THEN BEGIN
+            progress.Position:=done;
+            lbl_progress.Caption:='Files done: '+IntToStr(done)+'/'+IntToStr(files);
+            Application.ProcessMessages;
+          END;
+        END;
+      END ELSE BEGIN
+        files:=list.Count;
+        lbl_progress.Caption:='Files done: 0/'+IntToStr(files);
+        progress.Max:=files;
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF one_file THEN BEGIN
+            ExportFile(StrToInt(MidStr(list.Items.Strings[i],1,5)),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+          END ELSE BEGIN
+            ExportFile(StrToInt(MidStr(list.Items.Strings[i],1,5)),list.Items.Strings[i],settings,'D:');
+          END;
+          IF ((i MOD 10)=0) AND (i>=50) THEN
+            lbl_estimated.Caption:='Estimated finishing time: '+TimeToStr((Time-begintime)/i*files+begintime);
+          IF (i MOD 5)=0 THEN BEGIN
+            progress.Position:=i;
+            lbl_progress.Caption:='Files done: '+IntToStr(i)+'/'+IntToStr(files);
+            Application.ProcessMessages;
+          END;
+        END;
+      END;
+      group_progress.Visible:=False;
+      group_select.Enabled:=True;
+      group_singlefiles.Enabled:=True;
+      group_onefile.Enabled:=True;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.23a/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.23a/Unit12_ValueEdit.dfm	(revision 23)
+++ /oup/releases/0.23a/Unit12_ValueEdit.dfm	(revision 23)
@@ -0,0 +1,157 @@
+object Form12: TForm12
+  Left = 0
+  Top = 0
+  BorderStyle = bsNone
+  BorderWidth = 1
+  Caption = 'Value Edit'
+  ClientHeight = 145
+  ClientWidth = 298
+  Color = clBtnFace
+  Constraints.MaxHeight = 147
+  Constraints.MaxWidth = 700
+  Constraints.MinHeight = 147
+  Constraints.MinWidth = 300
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  PixelsPerInch = 96
+  TextHeight = 13
+  object group: TGroupBox
+    Left = 0
+    Top = 0
+    Width = 298
+    Height = 145
+    Align = alClient
+    Caption = '---'
+    TabOrder = 0
+    DesignSize = (
+      298
+      145)
+    object lbl_current: TLabel
+      Left = 8
+      Top = 64
+      Width = 73
+      Height = 17
+      AutoSize = False
+      Caption = 'Current value:'
+    end
+    object lbl_new: TLabel
+      Left = 8
+      Top = 88
+      Width = 73
+      Height = 17
+      AutoSize = False
+      Caption = 'New value:'
+    end
+    object lbl_offset: TLabel
+      Left = 8
+      Top = 16
+      Width = 73
+      Height = 17
+      AutoSize = False
+      Caption = 'Offset:'
+    end
+    object lbl_datatype: TLabel
+      Left = 8
+      Top = 40
+      Width = 73
+      Height = 17
+      AutoSize = False
+      Caption = 'Datatype:'
+    end
+    object btn_ok: TButton
+      Left = 153
+      Top = 112
+      Width = 65
+      Height = 25
+      Anchors = [akTop, akRight]
+      Caption = 'OK'
+      Default = True
+      TabOrder = 0
+      OnClick = btn_okClick
+    end
+    object btn_cancel: TButton
+      Left = 225
+      Top = 112
+      Width = 65
+      Height = 25
+      Anchors = [akTop, akRight]
+      Cancel = True
+      Caption = 'Cancel'
+      TabOrder = 1
+      OnClick = btn_cancelClick
+    end
+    object edit_current: TEdit
+      Left = 88
+      Top = 64
+      Width = 203
+      Height = 18
+      Anchors = [akLeft, akTop, akRight]
+      AutoSize = False
+      Color = clInfoBk
+      ReadOnly = True
+      TabOrder = 2
+    end
+    object edit_offset: TEdit
+      Left = 87
+      Top = 16
+      Width = 203
+      Height = 18
+      Anchors = [akLeft, akTop, akRight]
+      AutoSize = False
+      Color = clInfoBk
+      ReadOnly = True
+      TabOrder = 3
+    end
+    object edit_datatype: TEdit
+      Left = 87
+      Top = 40
+      Width = 203
+      Height = 18
+      Anchors = [akLeft, akTop, akRight]
+      AutoSize = False
+      Color = clInfoBk
+      ReadOnly = True
+      TabOrder = 4
+    end
+    object edit_new: TCrossEdit
+      Left = 88
+      Top = 88
+      Width = 203
+      Height = 18
+      Anchors = [akLeft, akTop, akRight]
+      AutoSize = False
+      BorderStyle = bsNone
+      Color = clWhite
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      HideSelection = False
+      ParentFont = False
+      TabOrder = 5
+      Text = '0000'
+      FocusAlignment = taLeftJustify
+      NoFocusAlignment = taLeftJustify
+      Precision = 15
+      Decimals = 4
+      FocusWidthInc = 0
+      EditType = etHex
+      NextDialogOnEnter = True
+      DialogOnCursorKeys = True
+      NextPriorStep = 1
+      AutoFocus = False
+      LimitCheck = True
+      Max = 2147483647.000000000000000000
+      FocusColor = clWhite
+      NoFocusColor = clWhite
+      ErrorColor = clRed
+      StringCharSet = scFull
+    end
+  end
+end
Index: /oup/releases/0.23a/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.23a/Unit12_ValueEdit.pas	(revision 23)
+++ /oup/releases/0.23a/Unit12_ValueEdit.pas	(revision 23)
@@ -0,0 +1,102 @@
+UNIT Unit12_ValueEdit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, CrossEdit, Math;
+TYPE
+  TForm12 = Class(TForm)
+    group: TGroupBox;
+    btn_ok: TButton;
+    btn_cancel: TButton;
+    lbl_current: TLabel;
+    edit_current: TEdit;
+    lbl_new: TLabel;
+    lbl_offset: TLabel;
+    lbl_datatype: TLabel;
+    edit_offset: TEdit;
+    edit_datatype: TEdit;
+    edit_new: TCrossEdit;
+    PROCEDURE btn_cancelClick(Sender: TObject);
+    PROCEDURE btn_okClick(Sender: TObject);
+    PROCEDURE MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form12: TForm12;
+
+
+IMPLEMENTATION
+USES Unit8_binedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win:TForm8;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win:=TForm8(caller);
+    Form1.Enabled:=False;
+    Self.Visible:=True;
+    group.Caption:='Edit value';
+    _datatype:=datatype;
+    _offset:=offset;
+    IF Length(objectname)>0 THEN group.Caption:=group.Caption+' for '+objectname;
+    edit_offset.Text:='0x'+IntToHex(offset,8);
+    edit_datatype.Text:=GetDataType(datatype);
+    edit_current.Text:=current;
+    edit_new.EditType:=etString;
+    edit_new.Text:='';
+    edit_new.LimitCheck:=False;
+    edit_new.MaxLength:=0;
+    edit_new.Max:=0;
+    Form12.Width:=300;
+    CASE datatype OF
+      1..4: BEGIN
+              edit_new.EditType:=etUnsignedInt;
+              edit_new.LimitCheck:=True;
+              edit_new.Max:=Int(Power(256,datatype))-1;
+            END;
+      5..8: BEGIN
+              edit_new.MaxLength:=2*(datatype-4);
+              edit_new.EditType:=etHex;
+            END;
+      9:    BEGIN
+              edit_new.EditType:=etFloat;
+              edit_new.LimitCheck:=False;
+            END;
+      10:   BEGIN
+              edit_new.EditType:=etBinary;
+              edit_new.LimitCheck:=False;
+              edit_new.MaxLength:=8;
+            END;
+      10000..65535: BEGIN
+              edit_new.EditType:=etString;
+              edit_new.LimitCheck:=False;
+              edit_new.MaxLength:=datatype-10000;
+              Form12.Width:=700;
+            END;
+    END;
+    edit_new.SetFocus;
+    edit_new.SelectAll;
+  END;
+
+PROCEDURE TForm12.btn_okClick(Sender: TObject);
+  BEGIN
+    IF NOT edit_new.NoValidValue THEN BEGIN
+      Form1.Enabled:=True;
+      Self.Visible:=False;
+      caller_win.SetNewValue(_datatype,_offset,edit_new.Text);
+    END;
+  END;
+
+PROCEDURE TForm12.btn_cancelClick(Sender: TObject);
+  BEGIN
+    Form1.Enabled:=True;
+    Self.Visible:=False;
+  END;
+
+END.
Index: /oup/releases/0.23a/Unit1_main.dfm
===================================================================
--- /oup/releases/0.23a/Unit1_main.dfm	(revision 23)
+++ /oup/releases/0.23a/Unit1_main.dfm	(revision 23)
@@ -0,0 +1,168 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 487
+  ClientWidth = 692
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIForm
+  Menu = menu
+  OldCreateOrder = False
+  WindowState = wsMaximized
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object statbar: TStatusBar
+    Left = 0
+    Top = 470
+    Width = 692
+    Height = 17
+    BiDiMode = bdLeftToRight
+    Panels = <
+      item
+        Text = 'Nothing loaded'
+        Width = 500
+      end
+      item
+        Text = 'Files: -'
+        Width = 90
+      end
+      item
+        Text = 'Extensions: -'
+        Width = 100
+      end>
+    ParentBiDiMode = False
+  end
+  object tabs: TTabSet
+    Left = 0
+    Top = 450
+    Width = 692
+    Height = 20
+    Align = alBottom
+    DitherBackground = False
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -11
+    Font.Name = 'Tahoma'
+    Font.Style = []
+    SoftTop = True
+    Style = tsModernTabs
+    OnChange = tabsChange
+  end
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 480
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 592
+    object menu_main: TMenuItem
+      Caption = '&Main'
+      object menu_loaddat: TMenuItem
+        Caption = '&Select .dat-file ...'
+        ShortCut = 16463
+        OnClick = menu_loaddatClick
+      end
+      object menu_lvldb: TMenuItem
+        Caption = 'Open OUP-Level-&DB ...'
+        ShortCut = 16452
+        OnClick = menu_lvldbClick
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      Enabled = False
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database'
+        Enabled = False
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files'
+        Enabled = False
+        OnClick = menu_createlvlClick
+      end
+    end
+    object menu_tools: TMenuItem
+      Caption = '&Tools'
+      Enabled = False
+      object menu_preview: TMenuItem
+        Caption = '&Preview Window ...'
+        ShortCut = 16464
+        OnClick = menu_previewClick
+      end
+      object menu_binedit: TMenuItem
+        Caption = '&Binary .dat editor ...'
+        ShortCut = 16450
+        OnClick = menu_bineditClick
+      end
+      object menu_txmpreplace: TMenuItem
+        Caption = '&TXMP replacer ...'
+        ShortCut = 16468
+        OnClick = menu_txmpreplaceClick
+      end
+      object menu_extractor: TMenuItem
+        Caption = 'File &extractor ...'
+        ShortCut = 16453
+        OnClick = menu_extractorClick
+      end
+      object menu_levelstructedit: TMenuItem
+        Caption = 'Levelfile structure editor ...'
+        Enabled = False
+        ShortCut = 16460
+      end
+    end
+    object menu_windows: TMenuItem
+      Caption = '&Windows'
+      object menu_windows_cascade: TMenuItem
+        Caption = 'Cascade'
+        OnClick = menu_windows_cascadeClick
+      end
+      object menu_windows_tile: TMenuItem
+        Caption = 'Tile'
+        OnClick = menu_windows_tileClick
+      end
+      object menu_windows_closeall: TMenuItem
+        Caption = '&Close all'
+        OnClick = menu_windows_closeallClick
+      end
+      object menu_sep3: TMenuItem
+        Caption = '-'
+      end
+      object menu_windows_next: TMenuItem
+        Caption = 'Next window'
+        ShortCut = 16417
+        OnClick = menu_windows_nextClick
+      end
+      object menu_windows_previous: TMenuItem
+        Caption = 'Previous window'
+        ShortCut = 16418
+        OnClick = menu_windows_previousClick
+      end
+      object menu_sep2: TMenuItem
+        Caption = '-'
+      end
+    end
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 520
+  end
+end
Index: /oup/releases/0.23a/Unit1_main.pas
===================================================================
--- /oup/releases/0.23a/Unit1_main.pas	(revision 23)
+++ /oup/releases/0.23a/Unit1_main.pas	(revision 23)
@@ -0,0 +1,435 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus, Grids,
+  MPHexEditor, ToolWin, ImgList, Tabs,
+  Unit2_functions, Unit3_data,
+  Unit10_leveldb, Unit4_exporters,
+  Unit5_preview, Unit7_txmpreplace, Unit8_binedit, Unit11_extractor;
+
+TYPE
+  TForm1 = Class(TForm)
+    tabs: TTabSet;
+    saved: TSaveDialog;
+    opend: TOpenDialog;
+    statbar: TStatusBar;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_loaddat: TMenuItem;
+    menu_lvldb: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_convert: TMenuItem;
+    menu_createdb: TMenuItem;
+    menu_createlvl: TMenuItem;
+    menu_tools: TMenuItem;
+    menu_preview: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    menu_binedit: TMenuItem;
+    menu_extractor: TMenuItem;
+    menu_windows: TMenuItem;
+    menu_windows_cascade: TMenuItem;
+    menu_windows_tile: TMenuItem;
+    menu_windows_closeall: TMenuItem;
+    menu_windows_next: TMenuItem;
+    menu_windows_previous: TMenuItem;
+    menu_sep1: TMenuItem;
+    menu_sep2: TMenuItem;
+    menu_sep3: TMenuItem;
+    menu_levelstructedit: TMenuItem;
+    PROCEDURE menu_createlvlClick(Sender: TObject);
+    PROCEDURE menu_extractorClick(Sender: TObject);
+    PROCEDURE menu_lvldbClick(Sender: TObject);
+    PROCEDURE menu_createdbClick(Sender: TObject);
+    PROCEDURE SetActiveWindow(window_name:String);
+    PROCEDURE tabsChange(Sender: TObject; NewTab: Integer; var AllowChange: Boolean);
+    PROCEDURE close_window(window_name:String);
+    PROCEDURE menu_windows_previousClick(Sender: TObject);
+    PROCEDURE menu_windows_nextClick(Sender: TObject);
+    PROCEDURE menu_windows_tileClick(Sender: TObject);
+    PROCEDURE open_child(window_context:String);
+    PROCEDURE menu_windows_closeallClick(Sender: TObject);
+    PROCEDURE menu_windows_cascadeClick(Sender: TObject);
+    PROCEDURE menu_window_entryClick(Sender: TObject);
+    PROCEDURE menu_bineditClick(Sender: TObject);
+    PROCEDURE menu_loaddatClick(Sender: TObject);
+    PROCEDURE menu_txmpreplaceClick(Sender: TObject);
+    PROCEDURE menu_exitClick(Sender: TObject);
+    PROCEDURE menu_previewClick(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form1: TForm1;
+
+IMPLEMENTATION
+{$R *.dfm}
+VAR
+  tablist:Array OF String;
+
+PROCEDURE TForm1.FormCreate(Sender: TObject);
+  BEGIN
+    Form1.Caption:='Oni Un/Packer '+version;
+    Form1.FormResize(Form1);
+
+    IF FileExists(ExtractFilepath(Application.EXEname)+'\oniunpacker.ini') THEN BEGIN
+      AssignFile(AppSettingsFile,ExtractFilepath(Application.EXEname)+'\oniunpacker.ini');
+      Reset(AppSettingsFile);
+      Read(AppSettingsFile,AppSettings);
+      CloseFile(AppSettingsFile);
+    END ELSE BEGIN
+      AppSettings.DatPath:='D:\Spiele\Oni\GameDataFolder';
+      AppSettings.ExtractPath:='C:\Dokumente und Einstellungen\Administrator\Desktop';
+    END;
+  END;
+
+PROCEDURE TForm1.FormResize(Sender: TObject);
+  CONST
+    MinWidth:Integer=750;
+    MinHeight:Integer=500;
+  BEGIN
+    IF Form1.Width<MinWidth THEN Form1.Width:=MinWidth;
+    IF Form1.Height<MinHeight THEN Form1.Height:=MinHeight;
+    Form1.statbar.Panels.Items[0].Width:=Form1.Width-200;
+  END;
+
+PROCEDURE TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    AssignFile(AppSettingsFile,ExtractFilepath(Application.EXEname)+'\oniunpacker.ini');
+    IF FileExists(ExtractFilepath(Application.EXEname)+'\oniunpacker.ini') THEN
+      Reset(AppSettingsFile)
+    ELSE
+      Rewrite(AppSettingsFile);
+    Write(AppSettingsFile,AppSettings);
+    CloseFile(AppSettingsFile);
+    Action:=caFree;
+  END;
+
+
+{#################################}
+{##### Main-Menu-Handlers    #####}
+{#################################}
+PROCEDURE TForm1.menu_loaddatClick(Sender: TObject);
+  VAR i:LongWord;
+  BEGIN
+    opend.InitialDir:=AppSettings.DatPath;
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    IF opend.Execute THEN BEGIN
+      menu_windows_closeallClick(Form1);
+      IF opened_state=opened_db THEN CloseDatabase;
+      IF Length(tablist)=0 THEN BEGIN
+        Caption:='Oni Un/Packer '+version;
+        statbar.Panels.Items[0].Text:='Nothing loaded';
+        statbar.Panels.Items[1].Text:='Files: -';
+        statbar.Panels.Items[2].Text:='Extensions: -';
+        AppSettings.DatPath:=ExtractFilepath(opend.FileName);
+        IF LoadDatInfos(opend.FileName) THEN BEGIN
+          Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(opend.FileName)+')';
+          statbar.Panels.Items[0].Text:='.dat loaded: '+dat_FileName;
+          statbar.Panels.Items[1].Text:='Files: '+IntToStr(dat_header.Files);
+          statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(dat_header.Extensions);
+          menu_tools.Enabled:=True;
+          menu_convert.Enabled:=True;
+          menu_createdb.Enabled:=True;
+          menu_createlvl.Enabled:=False;
+        END ELSE BEGIN
+          ShowMessage('Error while loading the file:'+CrLf+opend.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_lvldbClick(Sender: TObject);
+  BEGIN
+    opend.InitialDir:=AppSettings.DatPath;
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    IF opend.Execute THEN BEGIN
+      menu_windows_closeallClick(Form1);
+      IF opened_state=opened_db THEN CloseDatabase;
+      IF Length(tablist)=0 THEN BEGIN
+        Form1.Caption:='Oni Un/Packer '+version;
+        opened_state:=opened_nothing;
+        statbar.Panels.Items[0].Text:='Nothing loaded';
+        statbar.Panels.Items[1].Text:='Files: -';
+        statbar.Panels.Items[2].Text:='Extensions: -';
+        OpenDatabase(opend.FileName);
+        IF opened_state=opened_db THEN BEGIN
+          menu_tools.Enabled:=True;
+          menu_convert.Enabled:=True;
+          menu_createdb.Enabled:=False;
+          menu_createlvl.Enabled:=True;
+          statbar.Panels.Items[0].Text:='OLDB loaded: '+opend.FileName;
+          statbar.Panels.Items[1].Text:='Files: '+IntToStr(Length(GetFilesList('','',False)));
+          statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(GetExtensionsList));
+        END ELSE BEGIN
+          menu_tools.Enabled:=False;
+          menu_convert.Enabled:=False;
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+      saved.DefaultExt:='oldb';
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    BEGIN END;
+  END;
+
+{#################################}
+{##### Tools-Menu-Handlers   #####}
+{#################################}
+PROCEDURE TForm1.menu_previewClick(Sender: TObject);
+  BEGIN
+    open_child('preview');
+  END;
+PROCEDURE TForm1.menu_txmpreplaceClick(Sender: TObject);
+  BEGIN
+    open_child('txmpreplace');
+  END;
+PROCEDURE TForm1.menu_bineditClick(Sender: TObject);
+  BEGIN
+    open_child('binedit');
+  END;
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+
+{#################################}
+{#####  Window-Menu-Handlers #####}
+{#################################}
+PROCEDURE TForm1.menu_windows_cascadeClick(Sender: TObject);
+  BEGIN
+    Form1.Cascade;
+  END;
+PROCEDURE TForm1.menu_windows_tileClick(Sender: TObject);
+  BEGIN
+    Form1.TileMode:=tbHorizontal;
+    Form1.Tile;
+  END;
+PROCEDURE TForm1.menu_windows_closeallClick(Sender: TObject);
+  VAR
+    i:Byte;
+  BEGIN
+    IF MDIChildCount>0 THEN BEGIN
+      FOR i:=0 TO MDIChildCount-1 DO BEGIN
+        MDIChildren[i].Close;
+      END;
+    END;
+    tabs.Tabs.Clear;
+  END;
+PROCEDURE TForm1.menu_windows_nextClick(Sender: TObject);
+  VAR i:Byte;
+    first_window:Byte;
+    current_focus:String;
+  BEGIN
+    IF MDIChildCount>1 THEN BEGIN
+      FOR i:=0 TO menu_windows.Count-1 DO BEGIN
+        IF Pos('menu_window_',menu_windows.Items[i].Name)=1 THEN BEGIN
+          first_window:=i;
+          Break;
+        END;
+      END;
+      current_focus:=ActiveMDIChild.Name;
+      FOR i:=first_window TO menu_windows.Count-1 DO
+        IF Pos(current_focus,menu_windows.Items[i].Name)>0 THEN
+          Break;
+      IF i=menu_windows.Count-1 THEN
+        menu_windows.Items[first_window].Click
+      ELSE
+        menu_windows.Items[i+1].Click;
+      FOR i:=0 TO High(tablist) DO BEGIN
+        IF tablist[i]=ActiveMDIChild.Name THEN BEGIN
+          tabs.TabIndex:=i;
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_windows_previousClick(Sender: TObject);
+  VAR i:Byte;
+    first_window:Byte;
+    current_focus:String;
+  BEGIN
+    IF MDIChildCount>1 THEN BEGIN
+      FOR i:=0 TO menu_windows.Count-1 DO BEGIN
+        IF Pos('menu_window_',menu_windows.Items[i].Name)=1 THEN BEGIN
+          first_window:=i;
+          Break;
+        END;
+      END;
+      current_focus:=ActiveMDIChild.Name;
+      FOR i:=first_window TO menu_windows.Count-1 DO
+        IF Pos(current_focus,menu_windows.Items[i].Name)>0 THEN
+          Break;
+      IF i=first_window THEN
+        menu_windows.Items[menu_windows.Count-1].Click
+      ELSE
+        menu_windows.Items[i-1].Click;
+      FOR i:=0 TO High(tablist) DO BEGIN
+        IF tablist[i]=ActiveMDIChild.Name THEN BEGIN
+          tabs.TabIndex:=i;
+        END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm1.menu_window_entryClick(Sender: TObject);
+  VAR
+    i:Byte;
+    window_name:String;
+  BEGIN
+    window_name:=MidStr(TComponent(Sender).Name,Pos('window_',TComponent(Sender).Name)+7,Length(TComponent(Sender).Name)-Pos('window_',TComponent(Sender).Name)+7+1);
+    FOR i:=0 TO MDIChildCount-1 DO BEGIN
+      IF MDIChildren[i].Name=window_name THEN BEGIN
+        MDIChildren[i].BringToFront;
+      END;
+    END;
+    FOR i:=0 TO High(tablist) DO BEGIN
+      IF tablist[i]=ActiveMDIChild.Name THEN BEGIN
+        tabs.TabIndex:=i;
+      END;
+    END;
+  END;
+
+
+
+PROCEDURE TForm1.open_child(window_context:String);
+  VAR
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    FOR i:=1 TO 9 DO used[i]:=False;
+    IF MDIChildCount>0 THEN
+      FOR i:=0 TO MDIChildCount-1 DO
+        IF Pos(window_context,Form1.MDIChildren[i].Name)=1 THEN
+          used[StrToInt(RightStr(Form1.MDIChildren[i].Caption,1))]:=True;
+    FOR i:=1 TO 10 DO
+      IF i=10 THEN
+        Break
+      ELSE
+        IF NOT used[i] THEN Break;
+
+    IF i<10 THEN BEGIN
+      name:=window_context+IntToStr(i);
+      IF window_context='binedit' THEN
+        caption:='Binary .dat-Editor '+IntToStr(i);
+      IF window_context='preview' THEN
+        caption:='Preview-Window '+IntToStr(i);
+      IF window_context='txmpreplace' THEN
+        caption:='TXMP Replacer '+IntToStr(i);
+      IF window_context='extractor' THEN
+        caption:='Extractor '+IntToStr(i);
+
+      menu_button:=TMenuItem.Create(menu_windows);
+      menu_button.Caption:=caption;
+      menu_button.Name:='menu_window_'+name;
+      menu_button.OnClick:=Form1.menu_window_entryClick;
+      menu_windows.Add(menu_button);
+
+      SetLength(tablist,Length(tablist)+1);
+      tablist[High(tablist)]:=name;
+      tabs.Tabs.Add(caption);
+
+      IF window_context='binedit' THEN BEGIN
+        binEdit:=TForm8.Create(Application);
+        binEdit.Name:=name;
+        binEdit.Caption:=caption;
+        binEdit.Recreatelist;
+      END;
+      IF window_context='preview' THEN BEGIN
+        preview:=TForm5.Create(Application);
+        preview.Name:=name;
+        preview.Caption:=caption;
+        preview.Recreatelist;
+      END;
+      IF window_context='txmpreplace' THEN BEGIN
+        txmpreplacer:=TForm7.Create(Application);
+        txmpreplacer.Name:=name;
+        txmpreplacer.Caption:=caption;
+        txmpreplacer.Recreatelist;
+      END;
+      IF window_context='extractor' THEN BEGIN
+        extractor:=TForm11.Create(Application);
+        extractor.Name:=name;
+        extractor.Caption:=caption;
+        extractor.Recreatelist;
+      END;
+
+      tabs.TabIndex:=High(tablist);
+      IF MDIChildCount=9 THEN menu_tools.Enabled:=False;
+    END;
+  END;
+
+
+PROCEDURE TForm1.close_window(window_name:String);
+  VAR
+    i,j:Byte;
+  BEGIN
+    FOR i:=0 TO menu_windows.Count-1 DO BEGIN
+      IF menu_windows.Items[i].Name='menu_window_'+window_name THEN BEGIN
+        menu_windows.Items[i].Free;
+        Break;
+      END;
+    END;
+    FOR i:=0 TO High(tablist) DO BEGIN
+      IF tablist[i]=window_name THEN BEGIN
+        tabs.Tabs.Delete(i);
+        IF High(tablist)>0 THEN
+          FOR j:=i TO High(tablist)-1 DO
+            tablist[j]:=tablist[j+1];
+        SetLength(tablist,Length(tablist)-1);
+        Break;
+      END;
+    END;
+    menu_tools.Enabled:=True;
+  END;
+
+
+PROCEDURE TForm1.tabsChange(Sender: TObject; NewTab: Integer; var AllowChange: Boolean);
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=0 TO MDIChildCount-1 DO BEGIN
+      IF MDIChildren[i].Name=tablist[NewTab] THEN
+        MDIChildren[i].BringToFront;
+    END;
+  END;
+
+PROCEDURE TForm1.SetActiveWindow(window_name:String);
+  VAR
+    i:Byte;
+  BEGIN
+    IF Length(tablist)>0 THEN
+      FOR i:=0 TO High(tablist) DO
+        IF tablist[i]=window_name THEN
+          tabs.TabIndex:=i;
+  END;
+
+
+END.
Index: /oup/releases/0.23a/Unit2_functions.pas
===================================================================
--- /oup/releases/0.23a/Unit2_functions.pas	(revision 23)
+++ /oup/releases/0.23a/Unit2_functions.pas	(revision 23)
@@ -0,0 +1,538 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data, Unit4_Exporters, ABSDecUtil, ABSMain, DB;
+
+TYPE
+  TExportSet=SET OF (DO_dat,DO_raw,DO_convert,DO_toone);
+
+FUNCTION GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringList;
+FUNCTION GetExtensionsList:TStringList;
+
+FUNCTION Decode_Int(buffer:Tdata):LongWord;
+FUNCTION Encode_Int(input:LongWord):Tdata;
+FUNCTION Decode_Float(buffer:Tdata):Single;
+FUNCTION Encode_Float(input:Single):Tdata;
+FUNCTION DataToBin(data:Tdata):String;
+FUNCTION BinToInt(bin:String):Byte;
+
+FUNCTION GetFileInfo(fileid:LongWord):TFileInfo;
+FUNCTION LoadDatInfos(filename:String):Boolean;
+PROCEDURE OpenDatabase(FileName:String);
+PROCEDURE CloseDatabase;
+
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+PROCEDURE UpdateDatFile(fileid:LongWord; data:Tdata);
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+
+FUNCTION LoadRawFile(fileid,datlinkoffset,size:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateRawFile(fileid,datlinkoffset,size:LongWord; target:Pointer):Boolean;
+
+FUNCTION ExportFile(fileid:LongWord; filename:String; settings:TExportSet; path:String):Integer;
+
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION GetWinFileName(name:String):String;
+FUNCTION GetExtractPath:String;
+
+
+IMPLEMENTATION
+
+VAR
+  Database:TABSDatabase;
+  Query:TABSQuery;
+
+TYPE
+  TValueSwitcher=Record
+    CASE IsFloat: Boolean OF
+      True: (ValueFloat:Single);
+      False: (ValueInt:LongWord);
+  END;
+
+FUNCTION Decode_Int(buffer:Tdata):LongWord;
+  BEGIN
+    Result:=buffer[0]+buffer[1]*256+buffer[2]*256*256+buffer[3]*256*256*256;
+  END;
+FUNCTION Encode_Int(input:LongWord):Tdata;
+  BEGIN
+    SetLength(Result,4);
+    Result[0]:=input MOD 256;
+    input:=input DIV 256;
+    Result[1]:=input MOD 256;
+    input:=input DIV 256;
+    Result[2]:=input MOD 256;
+    input:=input DIV 256;
+    Result[3]:=input MOD 256;
+  END;
+FUNCTION Decode_Float(buffer:Tdata):Single;
+  VAR _valueswitcher:TValueSwitcher;
+  BEGIN
+    _valueswitcher.ValueInt:=Decode_Int(buffer);
+    Result:=_valueswitcher.ValueFloat;
+  END;
+FUNCTION Encode_Float(input:Single):Tdata;
+  VAR _valueswitcher:TValueSwitcher;
+  BEGIN
+    _valueswitcher.ValueFloat:=input;
+    Result:=Encode_Int(_valueswitcher.ValueInt);
+  END;
+
+FUNCTION DataToBin(data:Tdata):String;
+  VAR
+    i,j:Byte;
+    singlebyte:Byte;
+    bytepart:String;
+  BEGIN
+    SetLength(bytepart,8);
+    Result:='';
+    FOR i:=0 TO High(data) DO BEGIN
+      singlebyte:=data[i];
+      FOR j:=7 DOWNTO 0 DO BEGIN
+        bytepart[j+1]:=Char((singlebyte AND $01)+48);
+        singlebyte:=singlebyte SHR 1;
+      END;
+      Result:=Result+bytepart+' ';
+    END;
+  END;
+FUNCTION BinToInt(bin:String):Byte;
+  VAR
+    Add: Integer;
+    i: Byte;
+  BEGIN
+    Result:=0;
+    IF Length(bin)<>8 THEN Exit;
+    Add:=1;
+    FOR i:=8 DOWNTO 1 DO BEGIN
+      IF NOT (bin[i] IN ['0','1']) THEN Exit;
+      IF bin[i] = '1' THEN Inc(Result,Add);
+      Add:=Add SHL 1;
+    END;
+  END;
+
+FUNCTION GetFileInfo(fileid:LongWord):TFileInfo;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=dat_files[fileid];
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT * FROM datfiles WHERE id='+IntToStr(fileid)+' ORDER BY id ASC;';
+      Query.Open;
+      IF Query.RecordCount=1 THEN BEGIN
+        Query.First;
+        Result.ID:=Query.FieldByName('id').AsInteger;
+        Result.Name:=Query.FieldByName('name').AsString;
+        Result.Extension:=Query.FieldByName('extension').AsString;
+        Result.FileName:=FormatNumber(Result.ID,5,'0')+'-'+Result.Name+'.'+Result.Extension;
+        Result.Size:=0;
+        Result.FileType:=Query.FieldByName('contenttype').AsInteger;
+        Result.DatAddr:=0;
+        Result.opened:=False;
+      END;
+      Query.Close;
+    END;
+  END;
+
+
+FUNCTION GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringList;
+  VAR
+    i:LongWord;
+    where:String;
+  BEGIN
+    SetLength(Result,0);
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO BEGIN
+        IF ( (Length(ext)=0) OR (dat_files[i].Extension=ext) ) AND
+             ( (Length(pattern)=0) OR (Pos(UpperCase(pattern),UpperCase(dat_files[i].Name))>0) ) THEN BEGIN
+          IF NoEmptyFiles THEN BEGIN
+            IF (dat_files[i].FileType AND $02)=0 THEN BEGIN
+              SetLength(Result,Length(Result)+1);
+              Result[High(Result)]:=dat_files[i].FileName;
+            END;
+          END ELSE BEGIN
+            SetLength(Result,Length(Result)+1);
+            Result[High(Result)]:=dat_files[i].FileName;
+          END;
+        END;
+      END;
+    END ELSE BEGIN
+      where:='';
+      IF Length(ext)>0 THEN BEGIN
+        IF Length(where)>0 THEN where:=where+' AND ';
+        where:=where+'(extension="'+ext+'")';
+      END;
+      IF Length(pattern)>0 THEN BEGIN
+        IF Length(where)>0 THEN where:=where+' AND ';
+        where:=where+'(name LIKE "%'+pattern+'%")';
+      END;
+      IF NoEmptyFiles THEN BEGIN
+        IF Length(where)>0 THEN where:=where+' AND ';
+        where:=where+'(contenttype<>2)';
+      END;
+      IF Length(where)>0 THEN where:=' WHERE '+where;
+      Query.SQL.Text:='SELECT id,name,extension FROM datfiles'+where+' ORDER BY id ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i]:=FormatNumber(Query.FieldByName('id').AsInteger,5,'0')+'-'+Query.FieldByName('name').AsString+'.'+Query.FieldByName('extension').AsString;
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+FUNCTION GetExtensionsList:TStringList;
+  VAR
+    i:LongWord;
+  BEGIN
+    SetLength(Result,0);
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+        SetLength(Result,Length(Result)+1);
+        WITH dat_extensionsmap[i] DO BEGIN
+          Result[High(Result)]:=Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+IntToStr(ExtCount)+')';
+        END;
+      END;
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT extension,count(extension) AS x FROM datfiles GROUP BY extension ORDER BY extension ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i]:=Query.FieldByName('extension').AsString+' ('+IntToStr(Query.FieldByName('x').AsInteger)+')';
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    opened_state:=opened_dat;
+    dat_filename:=filename;
+    raw_filename:=MidStr(filename,1,Length(filename)-3)+'raw';
+    dat_file:=TFileStream.Create(filename, fmOpenRead);
+    dat_file.Read(dat_header,SizeOf(dat_header));
+    FOR i:=0 TO High(dat_header.Ident) DO
+      IF dat_header.Ident[i]<>header_ident1[i] THEN BEGIN
+        Result:=False;
+        Exit;
+      END;
+    SetLength(dat_filesmap,dat_header.Files);
+    SetLength(dat_files,dat_header.Files);
+    FOR i:=0 TO dat_header.Files-1 DO dat_file.Read(dat_filesmap[i],SizeOf(dat_filesmap[i]));
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      dat_files[i].Extension:=dat_filesmap[i].Extension;
+      dat_files[i].Extension:=ReverseString(dat_files[i].Extension);
+      dat_files[i].Size:=dat_filesmap[i].FileSize;
+      dat_files[i].FileType:=dat_filesmap[i].FileType;
+      dat_files[i].DatAddr:=dat_filesmap[i].DataAddr-8+dat_header.DataAddr;
+      IF (dat_filesmap[i].FileType AND $01)=0 THEN BEGIN
+        dat_file.Seek(dat_filesmap[i].NameAddr+dat_header.NamesAddr,soFromBeginning);
+        SetLength(dat_files[i].Name,100);
+        dat_file.Read(dat_files[i].Name[1],100);
+        dat_files[i].Name:=MidStr(dat_files[i].Name,1+4,Pos(#0,dat_files[i].Name)-1-4);
+      END ELSE BEGIN
+        dat_files[i].Name:='';
+      END;
+      dat_files[i].FileName:=FormatNumber(i,5,'0')+'-'+dat_files[i].Name+'.'+dat_files[i].Extension;
+    END;
+    dat_file.Seek($40+dat_header.Files*$14,soFromBeginning);
+    SetLength(dat_namedfilesmap,dat_header.NamedFiles);
+    FOR i:=0 TO dat_header.NamedFiles-1 DO dat_file.Read(dat_namedfilesmap[i],SizeOf(dat_namedfilesmap[i]));
+
+    dat_file.Seek($40+dat_header.Files*$14+dat_header.NamedFiles*$8,soFromBeginning);
+    SetLength(dat_extensionsmap,dat_header.Extensions);
+    FOR i:=0 TO dat_header.Extensions-1 DO dat_file.Read(dat_extensionsmap[i],SizeOf(dat_extensionsmap[i]));
+
+    dat_file.Free;
+  END;
+
+
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+  VAR
+    dat_file:TFileStream;
+    mem:TStream;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      dat_file:=TFileStream.Create(dat_filename, fmOpenRead);
+      dat_file.Seek(dat_files[fileid].DatAddr,soFromBeginning);
+      SetLength(Result,dat_files[fileid].Size);
+      dat_file.Read(Result[0],dat_files[fileid].Size);
+      dat_file.Free;
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        SetLength(Result,mem.Size);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(Result[0],mem.Size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+PROCEDURE UpdateDatFile(fileid:LongWord; data:Tdata);
+  VAR
+    dat_file:TFileStream;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      dat_file:=TFileStream.Create(dat_filename, fmOpenReadWrite);
+      dat_file.Seek(dat_files[fileid].DatAddr,soFromBeginning);
+      dat_file.Write(data[0],Length(data));
+      dat_file.Free;
+    END ELSE BEGIN
+    END;
+  END;
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR
+    dat_file:TFileStream;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      dat_file:=TFileStream.Create(dat_filename, fmOpenRead);
+      Result:=True;
+      dat_file.Seek(dat_files[fileid].DatAddr+offset,soFromBeginning);
+      dat_file.Read(target^,size);
+      dat_file.Free;
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(offset,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR
+    dat_file:TFileStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      dat_file:=TFileStream.Create(dat_filename, fmOpenReadWrite);
+      Result:=True;
+      dat_file.Seek(dat_files[fileid].DatAddr+offset,soFromBeginning);
+      dat_file.Write(target^,size);
+      dat_file.Free;
+    END ELSE BEGIN
+    END;
+  END;
+
+FUNCTION LoadRawFile(fileid,datlinkoffset,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    raw_addr:LongWord;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      LoadDatFilePart(fileid,datlinkoffset,4,@raw_addr);
+      filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+      filestream.Seek(raw_addr,soFromBeginning);
+      filestream.Read(target^,size);
+      filestream.Free;
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM rawmap WHERE src_id='+IntToStr(fileid)+';';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Result:=True;
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateRawFile(fileid,datlinkoffset,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    raw_addr:LongWord;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      LoadDatFilePart(fileid,datlinkoffset,4,@raw_addr);
+      filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenReadWrite);
+      filestream.Seek(raw_addr,soFromBeginning);
+      filestream.Write(target^,size);
+      filestream.Free;
+    END ELSE BEGIN
+    END;
+  END;
+
+
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+  BEGIN
+    Result:=AnsiReplaceStr(Format('%'+IntToStr(width)+'u',[value]),' ',leadingzeros);
+  END;
+
+FUNCTION FormatFileSize(size:LongWord):String;
+  BEGIN
+    IF size>=1000*1024*1024 THEN BEGIN
+      Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB';
+    END ELSE BEGIN
+      IF size>=1000*1024 THEN BEGIN
+        Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB';
+      END ELSE BEGIN
+        IF size>=1000 THEN BEGIN
+          Result:=FloatToStrF(size/1024,ffFixed,5,1)+' KB';
+        END ELSE BEGIN
+          Result:=IntToStr(size)+' B';
+        END;
+      END;
+    END;
+  END;
+
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+  VAR
+    string_build,ascii_version:String;
+    i:LongWord;
+  BEGIN
+    string_build:='';
+    ascii_version:='';
+    FOR i:=0 TO High(data) DO BEGIN
+      IF NOT HexOnly THEN
+        IF (i MOD 16)=0 THEN
+          string_build:=string_build+'0x'+IntToHex(i,6)+'  ';
+      string_build:=string_build+IntToHex(data[i],2);
+      IF NOT HexOnly THEN BEGIN
+        IF data[i]>=32 THEN ascii_version:=ascii_version+Chr(data[i])
+        ELSE ascii_version:=ascii_version+'.';
+        IF ((i+1) MOD 2)=0 THEN string_build:=string_build+#32;
+        IF ((i+1) MOD 16)=0 THEN BEGIN
+          string_build:=string_build+#32+ascii_version+CrLf;
+          ascii_version:='';
+        END;
+      END;
+    END;
+    Result:=string_build;
+  END;
+
+
+FUNCTION ExportFile(fileid:LongWord; filename:String; settings:TExportSet; path:String):Integer;
+  VAR
+    i:Byte;
+    extension:String;
+  BEGIN
+    Result:=export_noerror;
+    extension:=RightStr(filename,4);
+    IF DO_toone IN settings THEN BEGIN
+      ExportDatFile(fileid,path+'\'+GetWinFileName(filename));
+    END ELSE BEGIN
+      IF DO_dat IN settings THEN ExportDatFile(fileid,path+'\'+GetWinFileName(filename));
+      IF DO_raw IN settings THEN BEGIN
+        FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+          IF i<=Length(ExportHandlers) THEN BEGIN
+            IF ExportHandlers[i].Ext=extension THEN BEGIN
+              IF ExportHandlers[i].needed THEN BEGIN
+                CASE ExportHandlers[i].Handler(fileid,path+'\'+GetWinFileName(filename),(DO_convert IN settings)) OF
+                  0: Result:=0;
+                ELSE
+                  Result:=export_handlererror;
+                END;
+              END;
+              Break;
+            END;
+          END ELSE BEGIN
+            Result:=export_nohandler;
+          END;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(name:String):String;
+  BEGIN
+    Result:=name;
+    Result:=AnsiReplaceStr(Result,'\','__');
+    Result:=AnsiReplaceStr(Result,'/','__');
+    Result:=AnsiReplaceStr(Result,'>','__');
+    Result:=AnsiReplaceStr(Result,'<','__');
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+PROCEDURE OpenDatabase(FileName:String);
+  VAR
+    i:Byte;
+    temps:String;
+  BEGIN
+    IF NOT FileExists(FileName) THEN BEGIN
+      ShowMessage('File doesn''t exist!!!');
+      Exit;
+    END;
+    Database:=TABSDatabase.Create(NIL);
+    Database.DatabaseName:='OLDBcon';
+    Database.DatabaseFileName:=FileName;
+    Database.Open;
+    Query:=TABSQuery.Create(Database);
+    Query.DatabaseName:='OLDBcon';
+    Query.SQL.Text:='SELECT [name],[value] FROM globals ORDER BY [name] ASC';
+    Query.Open;
+    Query.First;
+    REPEAT
+      IF Query.FieldByName('name').AsString='dbversion' THEN BEGIN
+        IF Query.FieldByName('value').AsString<>DBversion THEN BEGIN
+          ShowMessage('Database-file '+CrLf+'"'+FileName+'"'+CrLf+'has wrong version. (Required: '+DBversion+'; found: '+Query.FieldByName('value').AsString+')');
+          Query.Close;
+          CloseDatabase;
+          Exit;
+        END;
+      END;
+      IF Query.FieldByName('name').AsString='lvl' THEN BEGIN
+        database_level:=StrToInt(Query.FieldByName('value').AsString);
+      END;
+      IF Query.FieldByName('name').AsString='ident' THEN BEGIN
+        temps:=Query.FieldByName('value').AsString;
+        FOR i:=0 TO High(database_ident) DO BEGIN
+          CASE temps[(i*2)+1+0] OF
+            '0'..'9': database_ident[i]:=Ord(temps[(i*2)+1+0])-48;
+            'A'..'F': database_ident[i]:=Ord(temps[(i*2)+1+0])-55;
+          END;
+          database_ident[i]:=database_ident[i]*16;
+          CASE temps[(i*2)+1+1] OF
+            '0'..'9': database_ident[i]:=database_ident[i]+Ord(temps[(i*2)+1+0])-48;
+            'A'..'F': database_ident[i]:=database_ident[i]+Ord(temps[(i*2)+1+0])-55;
+          END;
+        END;
+      END;
+      Query.Next;
+    UNTIL Query.Eof;
+    Query.Close;
+    opened_state:=opened_db;
+  END;
+PROCEDURE CloseDatabase;
+  BEGIN
+    Database.Close;
+    Database.Free;
+    opened_state:=opened_nothing;
+  END;
+
+
+
+END.
Index: /oup/releases/0.23a/Unit3_data.pas
===================================================================
--- /oup/releases/0.23a/Unit3_data.pas	(revision 23)
+++ /oup/releases/0.23a/Unit3_data.pas	(revision 23)
@@ -0,0 +1,102 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.23a';
+  dbversion:String='0.2';
+  CrLf:String[2]=#13+#10;
+
+TYPE
+  Tdata=Array OF Byte;
+  Theader=PACKED RECORD
+    Ident:Array[0..$13] OF Byte;
+    Files:LongWord;
+    NamedFiles:LongWord;
+    Extensions:LongWord;
+    DataAddr:LongWord;
+    DataSize:LongWord;
+    NamesAddr:LongWord;
+    NamesSize:LongWord;
+    Ident2:Array[0..$F] OF Byte;
+  END;
+  Tfilesmap=Array OF PACKED RECORD
+    Extension:Array[0..$3] OF Char;
+    DataAddr:LongWord;
+    NameAddr:LongWord;
+    FileSize:LongWord;
+    FileType:LongWord;
+  END;
+  TFileInfo=PACKED RECORD
+    ID:LongWord;
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+    opened:Boolean;
+  END;
+  Tfiles=Array OF TFileInfo;
+
+  Tnamedfilesmap=Array OF PACKED RECORD
+  	FileNumber:LongWord;
+	  blubb:LongWord;
+  END;
+  Textensionsmap=Array OF PACKED RECORD
+  	Ident:Array[0..$7] OF Byte;
+	  Extension:Array[0..$3] OF Char;
+  	ExtCount:LongWord;
+  END;
+
+  TAppSettings=RECORD
+    DatPath:String[250];
+    ExtractPath:String[250];
+  END;
+
+  TExportHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:Function(fileid:LongWord; filename:String; convert:Boolean):Integer;
+  END;
+
+  TStringList=Array OF String;
+  TExtList=Array OF RECORD
+    Ext:String;
+    count:LongWord;
+  END;
+
+VAR
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_header:Theader;
+  dat_filesmap:Tfilesmap;
+  dat_files:Tfiles;
+  dat_namedfilesmap:Tnamedfilesmap;
+  dat_extensionsmap:Textensionsmap;
+  AppSettings:TAppSettings;
+  AppSettingsFile:File OF TAppSettings;
+
+  database_level:LongWord;
+  database_ident:Array[0..$13] OF Byte;
+
+CONST
+  header_ident1:Array[0..$13] OF Byte=
+      ($1F,$27,$DC,$33,$DF,$BC,$03,$00,$31,$33,$52,$56,$40,$00,$14,$00,$10,$00,$08,$00);
+  header_ident2:Array[0..$F] OF Byte=
+      ($99,$CF,$40,$00,$90,$4F,$63,$00,$F4,$55,$5F,$00,$90,$4F,$63,$00);
+
+  export_noerror:Integer=0;
+  export_nohandler:Integer=1;
+  export_handlererror:Integer=2;
+  export_error:Integer=3;
+
+  opened_nothing:Byte=0;
+  opened_dat:Byte=1;
+  opened_db:Byte=2;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.23a/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.23a/Unit4_Exporters.pas	(revision 23)
+++ /oup/releases/0.23a/Unit4_Exporters.pas	(revision 23)
@@ -0,0 +1,200 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, Dialogs, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+
+FUNCTION ExportSNDD(fileid:LongWord; filename:String; convert:Boolean):Integer;
+FUNCTION ExportTRAC(fileid:LongWord; filename:String; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; filename:String; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; filename:String; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; filename:String; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..1] OF TExportHandlers=(
+//    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (Ext:'SNDD'; needed:True; Handler:ExportSNDD)
+{    (Ext:'TRAC'; needed:True; Handler:ExportTRAC),
+    (Ext:'TXAN'; needed:True; Handler:ExportTXAN),
+    (Ext:'TXMB'; needed:True; Handler:ExportTXMB),
+    (Ext:'TXMP'; needed:True; Handler:ExportTXMP)
+}  );
+
+
+
+IMPLEMENTATION
+USES Unit2_functions;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    IF FileExists(filename) THEN BEGIN
+      filestream:=TFileStream.Create(filename,fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd); 
+    END ELSE BEGIN
+      filestream:=TFileStream.Create(filename,fmCreate);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+FUNCTION ExportSNDD;
+{  CONST
+    WAVheader:Array[0..0] OF Byte=(
+        Ord('R'),Ord('I'),Ord('F'),Ord('F'),0,0,0,0,Ord('W'),Ord('A'),Ord('V'),Ord('E'),
+        Ord('f'),Ord('m'),Ord('t'),Ord(' '),24,0,0,0,
+      );
+}  TYPE
+    TDatData=RECORD
+      {0x00}
+      _fileid:LongWord;
+      level:LongWord;
+      Flag:LongWord;
+      FormatTag:Word;
+      ChanNo:Word;
+      {0x10}
+      SampleRate:LongWord;
+      BytesPSec:LongWord;
+      BPSample:LongWord;
+      BitsPS:LongWord;
+      {0x20}
+      Unknown:Array[1..7] OF LongWord;
+      Unknown2:Word;
+      {0x40}
+      RawSize:LongWord;
+      RawPos:LongWord;
+    END;
+  VAR
+  	filestream:TFileStream;
+
+    DatData:TDatData;
+  	//Wave Header Stuff
+	  ASCII_Group:LongWord; //"RIFF"
+  	WAV_Len:LongWord;
+	  ASCII_WAV:LongWord; //"WAVE"
+  	ASCII_FMT:LongWord; //"fmt "
+	  WAV_FMT_Len:LongWord;
+  	ASCII_DATA:LongWord; //"data"
+	  WAV_FolLen:LongWord;
+
+  	data:Tdata;
+  BEGIN
+	  Result:=export_noerror;
+    LoadDatFilePart(fileid,0,SizeOf(DatData),@DatData);
+    WITH DatData DO BEGIN
+    	//Initializing Header vars
+	    ASCII_Group:=1179011410; // 'RIFF'
+  	  WAV_Len:=RAWSize+70;
+  	  ASCII_WAV:=1163280727;  // 'WAVE'
+    	ASCII_FMT:=544501094;   // 'fmt '
+	    WAV_FMT_Len:=50;        // 50 bytes
+    	ASCII_DATA:=1635017060; // 'data'
+	    WAV_FolLen:=RAWSize;
+  	  SetLength(data,RAWSize);
+  	  LoadRawFile(fileid,68,Length(data),data);
+
+      filestream:=TFileStream.Create(filename+'.raw',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+
+      IF convert THEN BEGIN
+      	//Now start packing this into a neat wave...
+        filestream:=TFileStream.Create(filename+'.wav',fmCreate);
+    	  filestream.Write(ASCII_Group,SizeOf(ASCII_Group));
+  	    filestream.Write(WAV_Len,SizeOf(WAV_Len));
+    	  filestream.Write(ASCII_WAV,SizeOf(ASCII_WAV));
+  	    filestream.Write(ASCII_FMT,SizeOf(ASCII_FMT));
+    	  filestream.Write(WAV_FMT_Len,SizeOf(WAV_FMT_Len));
+  	    filestream.Write(ChanNo,SizeOf(ChanNo));
+      	filestream.Write(Samplerate,SizeOf(Samplerate));
+	      filestream.Write(BytesPSec,SizeOf(BytesPSec));
+  	    filestream.Write(BPSample,SizeOf(BPSample));
+    	  filestream.Write(BitsPS,SizeOf(BitsPS));
+      	filestream.Write(Unknown[1],SizeOf(Unknown));
+      	filestream.Write(Unknown2,SizeOf(Unknown2));
+      	filestream.Write(ASCII_DATA,SizeOf(ASCII_DATA));
+	      filestream.Write(WAV_FolLen,SizeOf(WAV_FolLen));
+    	  filestream.Write(data[0],Length(data));
+  	    filestream.Free;
+      END;
+    END;
+  END;
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+    END;
+  END;
+
+FUNCTION ExportTXAN;
+  VAR
+    loop_speed,unknown:Word;
+    linkcount:LongWord;
+    link:LongWord;
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$14,SizeOf(loop_speed),@loop_speed);
+    LoadDatFilePart(fileid,$16,SizeOf(unknown),@unknown);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      LoadDatFilePart(fileid,$20+i*4,SizeOf(link),@link);
+      link:=link DIV 256;
+      IF link=0 THEN link:=fileid-1;
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(filename+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    img:=LoadImgData(fileid);
+
+    filestream:=TFileStream.Create(filename+'.raw',fmCreate);
+    filestream.Write(img.imgdata[0],Length(img.imgdata));
+    filestream.Free;
+
+    IF convert THEN BEGIN
+      img.imgdata:=ImgdataToBMP(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(filename+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.23a/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.23a/Unit5_preview.dfm	(revision 23)
+++ /oup/releases/0.23a/Unit5_preview.dfm	(revision 23)
@@ -0,0 +1,192 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 480
+  Height = 500
+  Caption = 'Preview'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 473
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_preview: TPanel
+    Left = 159
+    Top = 0
+    Width = 313
+    Height = 473
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object img: TImage
+      Left = 0
+      Top = 20
+      Width = 313
+      Height = 453
+      Align = alClient
+    end
+    object lbl_notpossible: TLabel
+      Left = 16
+      Top = 56
+      Width = 97
+      Height = 65
+      AutoSize = False
+      Caption = 'No preview possible for this filetype'
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -16
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      ParentFont = False
+      Visible = False
+      WordWrap = True
+    end
+    object panel_buttons: TPanel
+      Left = 0
+      Top = 0
+      Width = 313
+      Height = 20
+      Align = alTop
+      BevelOuter = bvNone
+      TabOrder = 0
+      Visible = False
+      OnResize = panel_buttonsResize
+      object btn_dec: TButton
+        Left = 0
+        Top = 0
+        Width = 20
+        Height = 20
+        Caption = '-'
+        Enabled = False
+        TabOrder = 0
+        OnClick = btn_decClick
+      end
+      object btn_startstop: TButton
+        Left = 21
+        Top = 0
+        Width = 80
+        Height = 20
+        Caption = 'Stop automatic'
+        TabOrder = 1
+        OnClick = btn_startstopClick
+      end
+      object btn_inc: TButton
+        Left = 102
+        Top = 0
+        Width = 20
+        Height = 20
+        Caption = '+'
+        Enabled = False
+        TabOrder = 2
+        OnClick = btn_incClick
+      end
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 473
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 370
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 370
+      Width = 150
+      Height = 103
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object lbl_filter: TLabel
+        Left = 2
+        Top = 62
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = 'Filter by &extension:'
+        FocusControl = combo_extension
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 76
+        Width = 145
+        Height = 21
+        Style = csDropDownList
+        DropDownCount = 12
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Tahoma'
+        Font.Style = []
+        ItemHeight = 13
+        ParentFont = False
+        Sorted = True
+        TabOrder = 3
+        OnClick = combo_extensionClick
+      end
+      object check_zerobyte: TCheckBox
+        Left = 2
+        Top = 44
+        Width = 130
+        Height = 13
+        Caption = 'Show &zero-byte files'
+        TabOrder = 2
+        OnClick = check_zerobyteClick
+      end
+      object edit_filtername: TEdit
+        Left = 2
+        Top = 20
+        Width = 145
+        Height = 18
+        AutoSize = False
+        TabOrder = 1
+      end
+      object check_filtername: TCheckBox
+        Left = 2
+        Top = 5
+        Width = 130
+        Height = 15
+        Caption = 'Filter by file&name:'
+        TabOrder = 0
+        OnClick = check_filternameClick
+      end
+    end
+  end
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 144
+    Top = 24
+  end
+end
Index: /oup/releases/0.23a/Unit5_preview.pas
===================================================================
--- /oup/releases/0.23a/Unit5_preview.pas	(revision 23)
+++ /oup/releases/0.23a/Unit5_preview.pas	(revision 23)
@@ -0,0 +1,283 @@
+UNIT Unit5_preview;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Math, ExtCtrls, Unit2_functions, Unit3_data, Unit4_exporters, Unit6_imgfuncs,
+  StdCtrls, StrUtils, Menus;
+
+TYPE
+  TForm5 = Class(TForm)
+    timer: TTimer;
+    panel_preview: TPanel;
+    img: TImage;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    Splitter1: TSplitter;
+    lbl_notpossible: TLabel;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    check_zerobyte: TCheckBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE check_zerobyteClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormActivate(Sender: TObject);
+    PROCEDURE PreviewTXAN;
+    PROCEDURE PreviewTXMB;
+    PROCEDURE PreviewTXMP;
+    PROCEDURE btn_incClick(Sender: TObject);
+    PROCEDURE btn_decClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE btn_startstopClick(Sender: TObject);
+    PROCEDURE panel_buttonsResize(Sender: TObject);
+    PROCEDURE timerTimer(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  memstreams:Array OF TMemoryStream;
+  actualimg:Byte;
+  _fileid:LongWord;
+
+
+
+PROCEDURE TForm5.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=GetExtensionsList;
+    FOR i:=0 TO High(exts) DO
+      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm5.LoadFileNames;
+  VAR
+    Extension:String[4];
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    no_zero_bytes:=NOT check_zerobyte.Checked;
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN Extension:='';
+
+    files:=GetFilesList(extension,pattern,no_zero_bytes);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  END;
+
+PROCEDURE TForm5.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm5.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm5.check_zerobyteClick(Sender: TObject);
+  VAR
+    i:Byte;
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm5.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm5.listClick(Sender: TObject);
+  BEGIN
+    _fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
+    lbl_notpossible.Visible:=False;
+    Self.img.Visible:=True;
+    Self.timer.Enabled:=False;
+    Self.panel_buttons.Visible:=False;
+    IF RightStr(list.Items.Strings[list.ItemIndex],4)='TXAN' THEN PreviewTXAN
+    ELSE
+    IF RightStr(list.Items.Strings[list.ItemIndex],4)='TXMB' THEN PreviewTXMB
+    ELSE
+    IF RightStr(list.Items.Strings[list.ItemIndex],4)='TXMP' THEN PreviewTXMP
+    ELSE BEGIN
+      Self.lbl_notpossible.Visible:=True;
+      Self.img.Visible:=False;
+    END;
+  END;
+
+
+
+PROCEDURE TForm5.PreviewTXMB;
+  VAR
+    data:Tdata;
+    img:TImgPackage;
+  BEGIN
+    SetLength(memstreams,1);
+    img:=LoadTXMBconnected(_fileid);
+    data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+
+    memstreams[0].Clear;
+    memstreams[0].Write(data[0],Length(data));
+    memstreams[0].Seek(0,soFromBeginning);
+
+    Self.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE TForm5.PreviewTXMP;
+  VAR
+    data:Tdata;
+    img:TImgPackage;
+  BEGIN
+    SetLength(memstreams,1);
+    img:=LoadImgData(_fileid);
+    data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+
+    memstreams[0].Clear;
+    memstreams[0].Write(data[0],Length(data));
+    memstreams[0].Seek(0,soFromBeginning);
+
+    Self.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE TForm5.PreviewTXAN;
+  VAR
+    loop_speed:Word;
+    linkcount:LongWord;
+    link:LongWord;
+    i:Byte;
+    data:Tdata;
+    img:TImgPackage;
+  BEGIN
+    LoadDatFilePart(_fileid,$14,SizeOf(loop_speed),@loop_speed);
+    LoadDatFilePart(_fileid,$1C,SizeOf(linkcount),@linkcount);
+    SetLength(memstreams,linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      LoadDatFilePart(_fileid,$20+i*4,SizeOf(link),@link);
+      link:=link DIV 256;
+      IF link=0 THEN link:=_fileid-1;
+      memstreams[i]:=TMemoryStream.Create;
+      img:=LoadImgData(link);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      memstreams[i].Clear;
+      memstreams[i].Write(data[0],Length(data));
+      memstreams[i].Seek(0,soFromBeginning);
+    END;
+    actualimg:=254;
+    Self.timer.Interval:=Floor(loop_speed*(1/60)*1000);
+    Self.timer.Enabled:=False;
+    Self.btn_startstopClick(Self);
+    Self.panel_buttons.Visible:=True;
+  END;
+
+
+PROCEDURE TForm5.FormCreate(Sender: TObject);
+  BEGIN
+    SetLength(memstreams,1);
+    memstreams[0]:=TMemoryStream.Create;
+    Self.Width:=260;
+    Self.Height:=300;
+  END;
+
+PROCEDURE TForm5.timerTimer(Sender: TObject);
+  BEGIN
+    Inc(actualimg);
+    IF actualimg>=Length(memstreams) THEN actualimg:=0;
+    Self.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+    Self.Caption:='Preview '+GetFileInfo(_fileid).FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+  END;
+
+PROCEDURE TForm5.panel_buttonsResize(Sender: TObject);
+  BEGIN
+    btn_startstop.Width:=panel_buttons.Width-45;
+    btn_inc.Left:=panel_buttons.Width-23;
+  END;
+
+PROCEDURE TForm5.btn_startstopClick(Sender: TObject);
+  BEGIN
+    Self.timer.Enabled:=NOT Self.timer.Enabled;
+    Self.btn_dec.Enabled:=NOT Self.timer.Enabled;
+    Self.btn_inc.Enabled:=NOT Self.timer.Enabled;
+    IF Self.timer.Enabled THEN
+      Self.btn_startstop.Caption:='Stop automatic'
+    ELSE
+      Self.btn_startstop.Caption:='Start automatic';
+  END;
+
+PROCEDURE TForm5.FormResize(Sender: TObject);
+  BEGIN
+    IF Self.Width>=300 THEN BEGIN
+    END ELSE Self.Width:=300;
+    IF Self.Height>=200 THEN BEGIN
+    END ELSE Self.Height:=200;
+  END;
+
+PROCEDURE TForm5.btn_decClick(Sender: TObject);
+  BEGIN
+    IF actualimg>0 THEN
+      Dec(actualimg)
+    ELSE
+      actualimg:=High(memstreams);
+    Self.Caption:='Preview '+GetFileInfo(_fileid).FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Self.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+PROCEDURE TForm5.btn_incClick(Sender: TObject);
+  BEGIN
+    IF actualimg<High(memstreams) THEN
+      Inc(actualimg)
+    ELSE
+      actualimg:=0;
+    Self.Caption:='Preview '+GetFileInfo(_fileid).FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Self.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+
+PROCEDURE TForm5.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+
+PROCEDURE TForm5.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+END.
Index: /oup/releases/0.23a/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.23a/Unit6_imgfuncs.pas	(revision 23)
+++ /oup/releases/0.23a/Unit6_imgfuncs.pas	(revision 23)
@@ -0,0 +1,397 @@
+UNIT Unit6_imgfuncs;
+INTERFACE
+USES Math, Dialogs, SysUtils, Unit3_data;
+
+TYPE
+  TImgPackage=RECORD
+    imgx,imgy:Word;
+    imgdepth:Byte;
+    storetype:Byte;
+    datasize:LongWord;
+    raw_addr:LongWord;
+    imgdata:Tdata;
+  END;
+FUNCTION ResizeImage(oldx,oldy:LongWord; imgdepth:Byte; data:Tdata):Tdata;
+FUNCTION RevertImage(imgx,imgy,imgdepth:LongWord; imgdata:Tdata):Tdata;
+FUNCTION DecompressImage(imgx,imgy:LongWord; imgdata:Tdata):Tdata;
+FUNCTION ImgdataToBmp(imgx,imgy,imgdepth,storetype:LongWord; imgdata:Tdata):Tdata;
+FUNCTION BmpToImgdata(bmpdata:Tdata; _32bit:Boolean):TImgPackage;
+FUNCTION LoadTXMBconnected(fileid:LongWord):TImgPackage;
+FUNCTION LoadImgData(fileid:LongWord):TImgPackage;
+FUNCTION GetImageDataSize(imgx,imgy,imgdepth:Word; fading:Boolean):LongWord;
+FUNCTION CreateFadedImage(image:TImgPackage):Tdata;
+
+IMPLEMENTATION
+USES Unit2_functions;
+
+
+FUNCTION ResizeImage(oldx,oldy:LongWord; imgdepth:Byte; data:Tdata):Tdata;
+  VAR
+    i,j:LongWord;
+    col,row,row_orig:LongWord;
+    temparray:Tdata;
+  BEGIN
+    SetLength(temparray,(oldx DIV 2)*(oldy DIV 2)*(imgdepth DIV 8));
+    row_orig:=0;
+    row:=0;
+    col:=0;
+    FOR i:=0 TO (oldx*oldy)-1 DO BEGIN
+      IF ((i MOD oldx)=0) AND (i>0) THEN BEGIN
+        Inc(row_orig);
+        IF (row_orig MOD 2)=0 THEN BEGIN
+          Inc(row);
+          col:=0;
+        END;
+      END;
+      IF (row_orig MOD 2)=0 THEN BEGIN
+        IF (i MOD 2)=0 THEN BEGIN
+          FOR j:=0 TO (imgdepth DIV 8)-1 DO
+            temparray[((row*(oldx DIV 2))+col)*(imgdepth DIV 8)+j]:=data[i*2+j];
+          Inc(col);
+        END;
+      END;
+    END;
+    Result:=temparray;
+  END;
+
+
+FUNCTION RevertImage(imgx,imgy,imgdepth:LongWord; imgdata:Tdata):Tdata;
+  VAR
+    x,y,i:LongWord;
+  BEGIN
+    SetLength(Result,imgx*imgy*(imgdepth DIV 8));
+    FOR y:=0 TO imgy-1 DO
+      FOR x:=0 TO imgx-1 DO
+        FOR i:=0 TO (imgdepth DIV 8)-1 DO
+          Result[((imgx*(imgy-1-y)+x)*(imgdepth DIV 8))+i]:=
+                  imgdata[(imgx*y+x)*(imgdepth DIV 8)+i];
+  END;
+
+
+FUNCTION DecompressImage(imgx,imgy:LongWord; imgdata:Tdata):Tdata;
+  TYPE
+    Tcolor=RECORD
+        RGBb:Byte;
+        RGBg:Byte;
+        RGBr:Byte;
+        RGBa:Byte;
+      END;
+  VAR
+    i,j,x,y:LongWord;
+    color:Array[1..4] OF Tcolor;
+    pixel:Array[1..16] OF Byte;
+  BEGIN
+    x:=0;
+    y:=0;
+    SetLength(Result,imgx*imgy*4);
+    FOR i:=0 TO ((imgx*imgy) DIV 16)-1 DO BEGIN
+      Color[1].RGBb:=Floor(((imgdata[(i*8)+0]+imgdata[(i*8)+1]*256) AND $001F) / $001F * 255);
+      Color[1].RGBg:=Floor(((imgdata[(i*8)+0]+imgdata[(i*8)+1]*256) AND $07E0) / $07E0 * 255);
+      Color[1].RGBr:=Floor(((imgdata[(i*8)+0]+imgdata[(i*8)+1]*256) AND $F800) / $F800 * 255);
+      Color[1].RGBa:=255;
+      Color[2].RGBb:=Floor(((imgdata[(i*8)+2]+imgdata[(i*8)+3]*256) AND $001F) / $001F * 255);
+      Color[2].RGBg:=Floor(((imgdata[(i*8)+2]+imgdata[(i*8)+3]*256) AND $07E0) / $07E0 * 255);
+      Color[2].RGBr:=Floor(((imgdata[(i*8)+2]+imgdata[(i*8)+3]*256) AND $F800) / $F800 * 255);
+      Color[2].RGBa:=255;
+      Color[3].RGBb:=Floor( Color[1].RGBb/3*2 + Color[2].RGBb/3 );
+      Color[3].RGBg:=Floor( Color[1].RGBg/3*2 + Color[2].RGBg/3 );
+      Color[3].RGBr:=Floor( Color[1].RGBr/3*2 + Color[2].RGBr/3 );
+      Color[3].RGBa:=255;
+      Color[4].RGBb:=Floor( Color[1].RGBb/3 + Color[2].RGBb/3*2 );
+      Color[4].RGBg:=Floor( Color[1].RGBg/3 + Color[2].RGBg/3*2 );
+      Color[4].RGBr:=Floor( Color[1].RGBr/3 + Color[2].RGBr/3*2 );
+      Color[4].RGBa:=255;
+      Pixel[1]:=Floor( (imgdata[(i*8)+4] AND $C0) / $40 + 1 );
+      Pixel[2]:=Floor( (imgdata[(i*8)+4] AND $30) / $10 + 1 );
+      Pixel[3]:=Floor( (imgdata[(i*8)+4] AND $0C) / $04 + 1 );
+      Pixel[4]:=Floor( (imgdata[(i*8)+4] AND $03) + 1 );
+      Pixel[5]:=Floor( (imgdata[(i*8)+5] AND $C0) / $40 + 1 );
+      Pixel[6]:=Floor( (imgdata[(i*8)+5] AND $30) / $10 + 1 );
+      Pixel[7]:=Floor( (imgdata[(i*8)+5] AND $0C) / $04 + 1 );
+      Pixel[8]:=Floor( (imgdata[(i*8)+5] AND $03) + 1 );
+      Pixel[9]:=Floor( (imgdata[(i*8)+6] AND $C0) / $40 + 1 );
+      Pixel[10]:=Floor( (imgdata[(i*8)+6] AND $30) / $10 + 1 );
+      Pixel[11]:=Floor( (imgdata[(i*8)+6] AND $0C) / $04 + 1 );
+      Pixel[12]:=Floor( (imgdata[(i*8)+6] AND $03) + 1 );
+      Pixel[13]:=Floor( (imgdata[(i*8)+7] AND $C0) / $40 + 1 );
+      Pixel[14]:=Floor( (imgdata[(i*8)+7] AND $30) / $10 + 1 );
+      Pixel[15]:=Floor( (imgdata[(i*8)+7] AND $0C) / $04 + 1 );
+      Pixel[16]:=Floor( (imgdata[(i*8)+7] AND $03) + 1 );
+      FOR j:=0 TO 3 DO BEGIN
+        Result[((y+3)*imgx+x+j)*3+0]:=Color[Pixel[16-j]].RGBb;
+        Result[((y+3)*imgx+x+j)*3+1]:=Color[Pixel[16-j]].RGBg;
+        Result[((y+3)*imgx+x+j)*3+2]:=Color[Pixel[16-j]].RGBr;
+      END;
+      FOR j:=0 TO 3 DO BEGIN
+        Result[((y+2)*imgx+x+j)*3+0]:=Color[Pixel[12-j]].RGBb;
+        Result[((y+2)*imgx+x+j)*3+1]:=Color[Pixel[12-j]].RGBg;
+        Result[((y+2)*imgx+x+j)*3+2]:=Color[Pixel[12-j]].RGBr;
+      END;
+      FOR j:=0 TO 3 DO BEGIN
+        Result[((y+1)*imgx+x+j)*3+0]:=Color[Pixel[8-j]].RGBb;
+        Result[((y+1)*imgx+x+j)*3+1]:=Color[Pixel[8-j]].RGBg;
+        Result[((y+1)*imgx+x+j)*3+2]:=Color[Pixel[8-j]].RGBr;
+      END;
+      FOR j:=0 TO 3 DO BEGIN
+        Result[((y+0)*imgx+x+j)*3+0]:=Color[Pixel[4-j]].RGBb;
+        Result[((y+0)*imgx+x+j)*3+1]:=Color[Pixel[4-j]].RGBg;
+        Result[((y+0)*imgx+x+j)*3+2]:=Color[Pixel[4-j]].RGBr;
+      END;
+      x:=x+4;
+      IF x=imgx THEN BEGIN
+        y:=y+4;
+        x:=0;
+      END;
+    END;
+  END;
+
+
+FUNCTION ImgdataToBmp(imgx,imgy,imgdepth,storetype:LongWord; imgdata:Tdata):Tdata;
+  CONST BMPheader:Array[0..53] OF Byte=
+          ($42,$4D,0,0,0,0,0,0,0,0,54,0,0,0,
+           40,0,0,0,0,0,0,0,0,0,0,0,1,0,$18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+  VAR
+    i,x,y:LongWord;
+  BEGIN
+    CASE storetype OF
+      0: BEGIN
+          SetLength(Result,imgx*imgy*3);
+          FOR y:=0 TO imgy-1 DO BEGIN
+            FOR x:=0 TO imgx-1 DO BEGIN
+              Result[((imgx*y+x)*3)+0]:=Floor( ( (imgdata[(imgx*y+x)*2]+imgdata[(imgx*y+x)*2+1]*256) AND $000F ) / $000F * 255);
+              Result[((imgx*y+x)*3)+1]:=Floor( ( (imgdata[(imgx*y+x)*2]+imgdata[(imgx*y+x)*2+1]*256) AND $00F0 ) / $00F0 * 255);
+              Result[((imgx*y+x)*3)+2]:=Floor( ( (imgdata[(imgx*y+x)*2]+imgdata[(imgx*y+x)*2+1]*256) AND $0F00 ) / $0F00 * 255);
+            END;
+          END;
+        END;
+      1,2: BEGIN
+          SetLength(Result,imgx*imgy*3);
+          FOR y:=0 TO imgy-1 DO BEGIN
+            FOR x:=0 TO imgx-1 DO BEGIN
+              Result[((imgx*y+x)*3)+0]:=Floor( ( (imgdata[(imgx*y+x)*2]+imgdata[(imgx*y+x)*2+1]*256) AND $001F ) / $001F * 255);
+              Result[((imgx*y+x)*3)+1]:=Floor( ( (imgdata[(imgx*y+x)*2]+imgdata[(imgx*y+x)*2+1]*256) AND $03E0 ) / $03E0 * 255);
+              Result[((imgx*y+x)*3)+2]:=Floor( ( (imgdata[(imgx*y+x)*2]+imgdata[(imgx*y+x)*2+1]*256) AND $7C00 ) / $7C00 * 255);
+            END;
+          END;
+        END;
+      8: BEGIN
+          SetLength(Result,imgx*imgy*3);
+          FOR y:=0 TO imgy-1 DO BEGIN
+            FOR x:=0 TO imgx-1 DO BEGIN
+              Result[((imgx*y+x)*3)+0]:=imgdata[(imgx*y+x)*4+0];
+              Result[((imgx*y+x)*3)+1]:=imgdata[(imgx*y+x)*4+1];
+              Result[((imgx*y+x)*3)+2]:=imgdata[(imgx*y+x)*4+2];
+            END;
+          END;
+        END;
+      9: BEGIN
+          Result:=DecompressImage(imgx,imgy,imgdata);
+        END;
+    END;
+    Result:=RevertImage(imgx,imgy,24,Result);
+    SetLength(Result,imgx*imgy*3+54);
+    FOR i:=High(Result)-54 DOWNTO 0 DO   Result[i+54]:=Result[i];
+
+    FOR i:=0 TO High(BMPheader) DO   Result[i]:=BMPheader[i];
+    Result[2]:=((imgx*imgy*3+54) AND $000000FF);
+    Result[3]:=((imgx*imgy*3+54) AND $0000FF00) DIV $100;
+    Result[4]:=((imgx*imgy*3+54) AND $00FF0000) DIV $10000;
+    Result[5]:=((imgx*imgy*3+54) AND $FF000000) DIV $1000000;
+    Result[18]:=(imgx AND $000000FF) DIV $1;
+    Result[19]:=(imgx AND $0000FF00) DIV $100;
+    Result[20]:=(imgx AND $00FF0000) DIV $10000;
+    Result[21]:=(imgx AND $FF000000) DIV $1000000;
+    Result[22]:=(imgy AND $000000FF) DIV $1;
+    Result[23]:=(imgy AND $0000FF00) DIV $100;
+    Result[24]:=(imgy AND $00FF0000) DIV $10000;
+    Result[25]:=(imgy AND $FF000000) DIV $1000000;
+    Result[34]:=((imgx*imgy*3) AND $000000FF) DIV $1;
+    Result[35]:=((imgx*imgy*3) AND $0000FF00) DIV $100;
+    Result[36]:=((imgx*imgy*3) AND $00FF0000) DIV $10000;
+    Result[37]:=((imgx*imgy*3) AND $FF000000) DIV $1000000;
+  END;
+
+FUNCTION BmpToImgdata(bmpdata:Tdata; _32bit:Boolean):TImgPackage;
+  VAR
+    x,y:LongWord;
+    r24,g24,b24:Word;
+    r16,g16,b16:Word;
+    gesamt:Word;
+  BEGIN
+    Result.imgdepth:=0;
+    IF NOT((bmpdata[00]=$42) AND (bmpdata[01]=$4D)) THEN BEGIN
+      ShowMessage('Not a standard 24bit bitmap');
+      Exit;
+    END;
+    IF NOT(bmpdata[10]=54) THEN BEGIN
+      ShowMessage('Imagedata has to start at 0x54');
+      Exit;
+    END;
+    IF NOT(bmpdata[14]=40) THEN BEGIN
+      ShowMessage('Second bitmap header has to have 40 bytes');
+      Exit;
+    END;
+    IF NOT(bmpdata[28]=24) THEN BEGIN
+      ShowMessage('Bitmap has to have 24bits');
+      Exit;
+    END;
+    IF NOT(bmpdata[30]=0) THEN BEGIN
+      ShowMessage('Bitmap has to be uncompressed');
+      Exit;
+    END;
+    Result.imgx:=bmpdata[18]+bmpdata[19]*256+bmpdata[20]*256*256+bmpdata[21]*256*256*256;
+    Result.imgy:=bmpdata[22]+bmpdata[23]*256+bmpdata[24]*256*256+bmpdata[25]*256*256*256;
+    IF _32bit THEN BEGIN
+      Result.imgdepth:=32;
+      Result.storetype:=8;
+    END ELSE BEGIN
+      Result.imgdepth:=16;
+      Result.storetype:=1;
+    END;
+
+    SetLength(Result.imgdata,Result.imgx*Result.imgy*Result.imgdepth DIV 8);
+    IF _32bit THEN BEGIN
+      FOR y:=0 TO Result.imgy-1 DO BEGIN
+        FOR x:=0 TO Result.imgx-1 DO BEGIN
+          Result.imgdata[((Result.imgx*y+x)*4)+0]:=bmpdata[54+(Result.imgx*y+x)*3+0];
+          Result.imgdata[((Result.imgx*y+x)*4)+1]:=bmpdata[54+(Result.imgx*y+x)*3+1];
+          Result.imgdata[((Result.imgx*y+x)*4)+2]:=bmpdata[54+(Result.imgx*y+x)*3+2];
+          Result.imgdata[((Result.imgx*y+x)*4)+3]:=0;
+        END;
+      END;
+    END ELSE BEGIN
+      FOR y:=0 TO Result.imgy-1 DO BEGIN
+        FOR x:=0 TO Result.imgx-1 DO BEGIN
+          r24:=bmpdata[54+(Result.imgx*y+x)*3+0];
+          g24:=bmpdata[54+(Result.imgx*y+x)*3+1];
+          b24:=bmpdata[54+(Result.imgx*y+x)*3+2];
+          r16:=(Ceil(r24*$001F/255)) AND $001F;
+          g16:=(Ceil(g24*$03E0/255)) AND $03E0;
+          b16:=(Ceil(b24*$7C00/255)) AND $7C00;
+          gesamt:=r16+g16+b16;
+          Result.imgdata[((Result.imgx*y+x)*2)+0]:=gesamt AND $00FF;
+          Result.imgdata[((Result.imgx*y+x)*2)+1]:=(gesamt AND $FF00) DIV 256;
+        END;
+      END;
+    END;
+
+    Result.imgdata:=RevertImage(Result.imgx,Result.imgy,Result.imgdepth,Result.imgdata);
+  END;
+
+FUNCTION LoadTXMBconnected(fileid:LongWord):TImgPackage;
+  VAR
+    i,x,y,x2,y2,pixelid,imgid:LongWord;
+    rows,cols:Word;
+    linkcount:LongWord;
+    link:LongWord;
+    single_image:TImgPackage;
+    images_decoded:Array OF TImgPackage;
+    x_start,y_start:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$10,SizeOf(Result.imgx),@Result.imgx);
+    LoadDatFilePart(fileid,$12,SizeOf(Result.imgy),@Result.imgy);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    SetLength(images_decoded,linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      LoadDatFilePart(fileid,$20+i*4,SizeOf(link),@link);
+      link:=link DIV 256;
+      single_image:=LoadImgData(link);
+      images_decoded[i]:=BmpToImgdata(ImgdataToBmp(single_image.imgx,single_image.imgy,single_image.imgdepth,single_image.storetype,single_image.imgdata),False);
+    END;
+    SetLength(Result.imgdata,Result.imgx*Result.imgy*2);
+    FOR y:=0 TO rows-1 DO BEGIN
+      FOR x:=0 TO cols-1 DO BEGIN
+        imgid:=y*cols+x;
+        x_start:=0;
+        y_start:=0;
+        FOR i:=0 TO x DO   IF i<x THEN x_start:=x_start+images_decoded[i].imgx;
+        FOR i:=0 TO y DO   IF i<y THEN y_start:=y_start+images_decoded[i].imgy;
+        FOR y2:=0 TO images_decoded[imgid].imgy-1 DO BEGIN
+          FOR x2:=0 TO images_decoded[imgid].imgx-1 DO BEGIN
+            IF ( (x_start+x2)<Result.imgx ) AND ( (y_start+y2)<Result.imgy ) THEN BEGIN
+              pixelid:=y_start*Result.imgx+x_start+y2*Result.imgx+x2;
+              Result.imgdata[pixelid*2+0]:=images_decoded[imgid].imgdata[(y2*images_decoded[imgid].imgx+x2)*2+0];
+              Result.imgdata[pixelid*2+1]:=images_decoded[imgid].imgdata[(y2*images_decoded[imgid].imgx+x2)*2+1];
+            END;
+          END;
+        END;
+      END;
+    END;
+    Result.imgdepth:=16;
+    Result.storetype:=1;
+  END;
+
+FUNCTION LoadImgData(fileid:LongWord):TImgPackage;
+  BEGIN
+    LoadDatFilePart(fileid,$8C,SizeOf(Result.imgx),@Result.imgx);
+    LoadDatFilePart(fileid,$8E,SizeOf(Result.imgy),@Result.imgy);
+    LoadDatFilePart(fileid,$90,SizeOf(Result.storetype),@Result.storetype);
+
+    CASE Result.storetype OF
+      0,1,2: BEGIN
+          Result.datasize:=Result.imgx*Result.imgy*2;
+          Result.imgdepth:=16;
+        END;
+      8: BEGIN
+          Result.datasize:=Result.imgx*Result.imgy*4;
+          Result.imgdepth:=32;
+        END;
+      9: BEGIN
+          Result.datasize:=Result.imgx*Result.imgy DIV 2;
+          Result.imgdepth:=16;
+        END;
+    ELSE
+      Exit;
+    END;
+    SetLength(Result.imgdata,Result.datasize);
+
+    LoadRawFile(fileid,$9C,Result.datasize,@Result.imgdata[0]);
+  END;
+
+FUNCTION GetImageDataSize(imgx,imgy,imgdepth:Word; fading:Boolean):LongWord;
+  VAR
+    size:LongWord;
+    x,y:Word;
+  BEGIN
+    x:=imgx;
+    y:=imgy;
+    size:=x*y*imgdepth DIV 8;
+    IF fading THEN BEGIN
+      REPEAT
+        x:=x DIV 2;
+        y:=y DIV 2;
+        size:=size+x*y*imgdepth DIV 8;
+      UNTIL (x=1) OR (y=1);
+    END;
+    Result:=size;
+  END;
+
+FUNCTION CreateFadedImage(image:TImgPackage):Tdata;
+  VAR
+    i:LongWord;
+    x,y:Word;
+    imgdata:Tdata;
+    fadelvldata:Tdata;
+  BEGIN
+    x:=image.imgx;
+    y:=image.imgy;
+    SetLength(imgdata,x*y*image.imgdepth DIV 8);
+    SetLength(fadelvldata,x*y*image.imgdepth DIV 8);
+    FOR i:=0 TO Length(imgdata)-1 DO BEGIN
+      imgdata[i]:=image.imgdata[i];
+      fadelvldata[i]:=image.imgdata[i];
+    END;
+    REPEAT
+      fadelvldata:=ResizeImage(x,y,image.imgdepth DIV 8,fadelvldata);
+      x:=x DIV 2;
+      y:=y DIV 2;
+      SetLength(imgdata,Length(imgdata)+x*y*image.imgdepth DIV 8);
+      FOR i:=0 TO Length(fadelvldata)-1 DO imgdata[Length(imgdata)-x*y*image.imgdepth DIV 8+i]:=fadelvldata[i];
+    UNTIL (x=1) OR (y=1);
+    SetLength(Result, Length(imgdata));
+    FOR i:=0 TO Length(imgdata)-1 DO Result[i]:=imgdata[i];
+  END;
+
+END.
Index: /oup/releases/0.23a/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.23a/Unit7_txmpreplace.dfm	(revision 23)
+++ /oup/releases/0.23a/Unit7_txmpreplace.dfm	(revision 23)
@@ -0,0 +1,190 @@
+object Form7: TForm7
+  Left = 0
+  Top = 0
+  BorderStyle = bsSingle
+  Caption = 'TXMP Replacer'
+  ClientHeight = 428
+  ClientWidth = 394
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_12: TPanel
+    Left = 0
+    Top = 0
+    Width = 394
+    Height = 349
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter1: TSplitter
+      Left = 200
+      Top = 0
+      Width = 8
+      Height = 349
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object group_txmpselect: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 200
+      Height = 349
+      Align = alLeft
+      Caption = '1. Select TXMP to replace'
+      TabOrder = 0
+      object splitter_txmp: TSplitter
+        Left = 2
+        Top = 190
+        Width = 196
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 60
+      end
+      object image_txmppreview: TImage
+        Left = 2
+        Top = 198
+        Width = 196
+        Height = 119
+        Align = alClient
+      end
+      object list_txmp: TListBox
+        Left = 2
+        Top = 15
+        Width = 196
+        Height = 175
+        Align = alTop
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_txmpClick
+      end
+      object panel_txmppreview: TPanel
+        Left = 2
+        Top = 317
+        Width = 196
+        Height = 30
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        object btn_save: TButton
+          Left = 2
+          Top = 2
+          Width = 111
+          Height = 25
+          Caption = 'Save TXMP-Picture'
+          TabOrder = 0
+          OnClick = btn_saveClick
+        end
+      end
+    end
+    object group_bmpselect: TGroupBox
+      Left = 208
+      Top = 0
+      Width = 186
+      Height = 349
+      Align = alClient
+      Caption = '2. Open BMP to replace with'
+      Enabled = False
+      TabOrder = 1
+      object image_bmppreview: TImage
+        Left = 2
+        Top = 45
+        Width = 182
+        Height = 302
+        Align = alClient
+      end
+      object panel_load: TPanel
+        Left = 2
+        Top = 15
+        Width = 182
+        Height = 30
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_load: TButton
+          Left = 2
+          Top = 2
+          Width = 121
+          Height = 25
+          Caption = 'Load BMP ...'
+          TabOrder = 0
+          OnClick = btn_loadClick
+        end
+      end
+    end
+  end
+  object group_options: TGroupBox
+    Left = 0
+    Top = 349
+    Width = 394
+    Height = 79
+    Align = alBottom
+    Caption = '3. Options && Replace'
+    Enabled = False
+    TabOrder = 1
+    object btn_replace: TButton
+      Left = 4
+      Top = 50
+      Width = 157
+      Height = 25
+      Caption = 'Replace'
+      TabOrder = 0
+      OnClick = btn_replaceClick
+    end
+    object check_transparency: TCheckBox
+      Left = 8
+      Top = 16
+      Width = 105
+      Height = 17
+      Caption = 'Transparency'
+      TabOrder = 1
+    end
+    object check_fading: TCheckBox
+      Left = 8
+      Top = 32
+      Width = 105
+      Height = 17
+      Caption = 'Fading'
+      TabOrder = 2
+    end
+    object check_32bit: TCheckBox
+      Left = 112
+      Top = 16
+      Width = 105
+      Height = 17
+      Hint = 'Import bitmap as 32bit image (to prevent from quality loss)'
+      Caption = '32bit'
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 3
+    end
+  end
+  object opend: TOpenDialog
+    Filter = '24bit Bitmap (*.bmp)|*.bmp'
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 352
+    Top = 16
+  end
+  object saved: TSaveDialog
+    DefaultExt = 'bmp'
+    Filter = 'Windows Bitmap (*.bmp)|*.bmp'
+    Options = [ofOverwritePrompt, ofHideReadOnly, ofPathMustExist, ofEnableSizing]
+    Left = 104
+    Top = 320
+  end
+end
Index: /oup/releases/0.23a/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.23a/Unit7_txmpreplace.pas	(revision 23)
+++ /oup/releases/0.23a/Unit7_txmpreplace.pas	(revision 23)
@@ -0,0 +1,227 @@
+UNIT Unit7_txmpreplace;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ExtCtrls, StdCtrls, StrUtils, Unit2_functions, Unit3_data;
+
+TYPE
+  TForm7 = Class(TForm)
+    panel_12: TPanel;
+    group_txmpselect: TGroupBox;
+    splitter_txmp: TSplitter;
+    list_txmp: TListBox;
+    Splitter1: TSplitter;
+    group_bmpselect: TGroupBox;
+    panel_load: TPanel;
+    btn_load: TButton;
+    image_bmppreview: TImage;
+    opend: TOpenDialog;
+    group_options: TGroupBox;
+    btn_replace: TButton;
+    check_transparency: TCheckBox;
+    check_fading: TCheckBox;
+    check_32bit: TCheckBox;
+    panel_txmppreview: TPanel;
+    btn_save: TButton;
+    image_txmppreview: TImage;
+    saved: TSaveDialog;
+    PROCEDURE btn_saveClick(Sender: TObject);
+    PROCEDURE FormActivate(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE btn_replaceClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+    PROCEDURE list_txmpClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE Recreatelist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit6_imgfuncs;
+{$R *.dfm}
+VAR
+  actual_bmpdata:Tdata;
+
+PROCEDURE TForm7.Recreatelist;
+  VAR
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    list_txmp.Items.Clear;
+    files:=GetFilesList('TXMP','',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list_txmp.Items.Add(files[i]);
+    group_bmpselect.Enabled:=False;
+    check_transparency.Checked:=False;
+    check_fading.Checked:=False;
+  END;
+
+  
+PROCEDURE TForm7.FormResize(Sender: TObject);
+  BEGIN
+    IF Self.Width>=400 THEN BEGIN
+    END ELSE Self.Width:=400;
+    IF Self.Height>=350 THEN BEGIN
+    END ELSE Self.Height:=350;
+  END;
+
+PROCEDURE TForm7.list_txmpClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    data:Tdata;
+    img:TImgPackage;
+    mem:TMemoryStream;
+    fadingbyte,depthbyte,storebyte:Byte;
+  BEGIN
+    id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+
+    LoadDatFilePart(id,$88,SizeOf(fadingbyte),@fadingbyte);
+    LoadDatFilePart(id,$89,SizeOf(depthbyte),@depthbyte);
+    LoadDatFilePart(id,$90,SizeOf(storebyte),@storebyte);
+    check_fading.Checked:=(fadingbyte AND $01)>0;
+    check_transparency.Checked:=(depthbyte AND $04)>0;
+    check_32bit.Checked:=(storebyte=8);
+
+    img:=LoadImgData(id);
+    data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+
+    mem:=TMemoryStream.Create;
+    mem.Write(data[0],Length(data));
+    mem.Seek(0,soFromBeginning);
+    image_txmppreview.Picture.Bitmap.LoadFromStream(mem);
+    mem.Free;
+
+    group_bmpselect.Enabled:=True;
+  END;
+
+PROCEDURE TForm7.btn_loadClick(Sender: TObject);
+  VAR
+    bmpfile:TFileStream;
+    mem:TMemoryStream;
+  BEGIN
+    IF opend.Execute THEN BEGIN
+      bmpfile:=TFileStream.Create(opend.FileName, fmOpenRead);
+      SetLength(actual_bmpdata,bmpfile.Size);
+      bmpfile.Read(actual_bmpdata[0],bmpfile.Size);
+      bmpfile.Free;
+
+      mem:=TMemoryStream.Create;
+      mem.Write(actual_bmpdata[0],Length(actual_bmpdata));
+      mem.Seek(0,soFromBeginning);
+      image_bmppreview.Picture.Bitmap.LoadFromStream(mem);
+      mem.Free;
+
+      group_options.Enabled:=True;
+    END;
+  END;
+
+PROCEDURE TForm7.btn_replaceClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    imgpkg:TImgPackage;
+    rawfile:TFileStream;
+    dataddr:LongWord;
+    old_rawaddr,new_rawaddr:LongWord;
+    oldwidth,oldheight:Word;
+    oldstore,olddepth,oldfading:Byte;
+    oldsize:LongWord;
+    newsize:LongWord;
+    datbyte:Word;
+  BEGIN
+    IF list_txmp.ItemIndex>=0 THEN BEGIN
+      imgpkg:=BmpToImgdata(actual_bmpdata,check_32bit.Checked);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      LoadDatFilePart(id,$8C,2,@oldwidth);
+      LoadDatFilePart(id,$8E,2,@oldheight);
+      LoadDatFilePart(id,$88,1,@oldfading);
+      LoadDatFilePart(id,$89,1,@olddepth);
+      LoadDatFilePart(id,$90,1,@oldstore);
+      LoadDatFilePart(id,$9C,4,@old_rawaddr);
+      IF (oldwidth<>imgpkg.imgx) OR (oldheight<>imgpkg.imgy) THEN BEGIN
+        IF MessageBox(Self.Handle,
+                    PChar('Current image and new image have different size'+CrLf+
+                            '(Current: '+IntToStr(oldwidth)+'x'+IntToStr(oldheight)+
+                            ' - New: '+IntToStr(imgpkg.imgx)+'x'+IntToStr(imgpkg.imgy)+')'+CrLf+
+                            'Replace anyways?'),
+                    PChar(list_txmp.Items.Strings[list_txmp.ItemIndex]),
+                    MB_YESNO)=IDNO THEN Exit;
+      END;
+
+      rawfile:=TFileStream.Create(raw_filename,fmOpenReadWrite);
+
+      CASE oldstore OF
+        9: oldsize:=GetImageDataSize(oldwidth,oldheight,8,(oldfading AND $01)>0);
+        0,1,2: oldsize:=GetImageDataSize(oldwidth,oldheight,16,(oldfading AND $01)>0);
+        8: oldsize:=GetImageDataSize(oldwidth,oldheight,32,(oldfading AND $01)>0);
+      ELSE
+        oldsize:=0;
+      END;
+      IF check_32bit.Checked THEN
+        newsize:=GetImageDataSize(imgpkg.imgx,imgpkg.imgy,32,check_fading.Checked)
+      ELSE
+        newsize:=GetImageDataSize(imgpkg.imgx,imgpkg.imgy,16,check_fading.Checked);
+
+      IF newsize<=oldsize THEN
+        new_rawaddr:=old_rawaddr
+      ELSE
+        new_rawaddr:=rawfile.Size;
+
+      datbyte:=$00;
+      IF check_fading.Checked THEN datbyte:=datbyte OR $01;
+      UpdateDatFilePart(id,$88,1,@datbyte);
+      datbyte:=$10;
+      IF check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      UpdateDatFilePart(id,$89,1,@datbyte);
+      UpdateDatFilePart(id,$8C,2,@imgpkg.imgx);
+      UpdateDatFilePart(id,$8E,2,@imgpkg.imgy);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      UpdateDatFilePart(id,$90,1,@datbyte);
+      UpdateDatFilePart(id,$9C,4,@new_rawaddr);
+
+      IF check_fading.Checked THEN BEGIN
+        imgpkg.imgdata:=CreateFadedImage(imgpkg);
+      END;
+
+      rawfile.Seek(new_rawaddr,soFromBeginning);
+      rawfile.Write(imgpkg.imgdata[0],Length(imgpkg.imgdata));
+      rawfile.Free;
+      
+      ShowMessage('TXMP-image replaced');
+    END;
+  END;
+
+PROCEDURE TForm7.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm7.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm7.btn_saveClick(Sender: TObject);
+  VAR
+    filestream:TFileStream;
+    img:TImgPackage;
+  BEGIN
+    IF saved.Execute THEN BEGIN
+      img:=LoadImgData(StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5)));
+      img.imgdata:=ImgdataToBMP(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(saved.FileName,fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.23a/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.23a/Unit8_binedit.dfm	(revision 23)
+++ /oup/releases/0.23a/Unit8_binedit.dfm	(revision 23)
@@ -0,0 +1,293 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  Width = 650
+  Height = 450
+  Caption = 'Binary .dat-Editor'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 423
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 423
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    OnResize = panel_dataResize
+    object Splitter2: TSplitter
+      Left = 0
+      Top = 209
+      Width = 483
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+    end
+    object Splitter3: TSplitter
+      Left = 0
+      Top = 375
+      Width = 483
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 483
+      Height = 209
+      Cursor = crIBeam
+      Align = alTop
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -16
+      Font.Name = 'Courier'
+      Font.Style = []
+      ParentFont = False
+      TabOrder = 0
+      BytesPerRow = 16
+      Translation = tkASCII
+      OffsetFormat = '6!10:0x|'
+      Colors.Background = clWindow
+      Colors.ChangedBackground = clWindow
+      Colors.ChangedText = clRed
+      Colors.CursorFrame = clNavy
+      Colors.Offset = clBlack
+      Colors.OddColumn = clBlue
+      Colors.EvenColumn = clNavy
+      Colors.CurrentOffsetBackground = clBtnShadow
+      Colors.OffsetBackGround = clBtnFace
+      Colors.CurrentOffset = clBtnHighlight
+      Colors.Grid = clBtnFace
+      Colors.NonFocusCursorFrame = clAqua
+      Colors.ActiveFieldBackground = clWindow
+      FocusFrame = True
+      NoSizeChange = True
+      AllowInsertMode = False
+      DrawGridLines = False
+      Version = 'May 23, 2005; '#169' markus stephany, vcl[at]mirkes[dot]de'
+      OnChange = hexChange
+      ShowPositionIfNotFocused = True
+      OnSelectionChanged = hexSelectionChanged
+    end
+    object structs: TWrapGrid
+      Left = 0
+      Top = 383
+      Width = 483
+      Height = 40
+      Align = alBottom
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      TabOrder = 1
+      OnClick = structsClick
+      OnDblClick = structsDblClick
+    end
+    object value_viewer: TWrapGrid
+      Left = 0
+      Top = 218
+      Width = 483
+      Height = 157
+      Align = alClient
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      PopupMenu = value_viewer_context
+      TabOrder = 2
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 423
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Bevel1: TBevel
+      Left = 0
+      Top = 359
+      Width = 150
+      Height = 6
+      Align = alBottom
+      Style = bsRaised
+    end
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 256
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 256
+      Width = 150
+      Height = 103
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object lbl_filter: TLabel
+        Left = 2
+        Top = 62
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = 'Filter by &extension:'
+        FocusControl = combo_extension
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 76
+        Width = 145
+        Height = 21
+        Style = csDropDownList
+        DropDownCount = 12
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Tahoma'
+        Font.Style = []
+        ItemHeight = 13
+        ParentFont = False
+        Sorted = True
+        TabOrder = 3
+        OnClick = combo_extensionClick
+      end
+      object check_zerobyte: TCheckBox
+        Left = 2
+        Top = 44
+        Width = 130
+        Height = 13
+        Caption = 'Show &zero-byte files'
+        TabOrder = 2
+        OnClick = check_zerobyteClick
+      end
+      object edit_filtername: TEdit
+        Left = 2
+        Top = 20
+        Width = 145
+        Height = 18
+        AutoSize = False
+        TabOrder = 1
+      end
+      object check_filtername: TCheckBox
+        Left = 2
+        Top = 5
+        Width = 130
+        Height = 15
+        Caption = 'Filter by file&name:'
+        TabOrder = 0
+        OnClick = check_filternameClick
+      end
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 365
+      Width = 150
+      Height = 58
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 2
+      OnResize = panel_imexportResize
+      object btn_export: TButton
+        Left = 4
+        Top = 4
+        Width = 142
+        Height = 25
+        Caption = 'Export to file...'
+        TabOrder = 0
+        OnClick = btn_exportClick
+      end
+      object btn_import: TButton
+        Left = 4
+        Top = 32
+        Width = 142
+        Height = 25
+        Caption = 'Import from file...'
+        TabOrder = 1
+        OnClick = btn_importClick
+      end
+    end
+  end
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 392
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 368
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 240
+    Top = 248
+    object value_viewer_context_copy: TMenuItem
+      Caption = 'Copy to &clipboard'
+      OnClick = value_viewer_context_copyClick
+    end
+    object value_viewer_context_copyasdec: TMenuItem
+      Caption = 'Copy to clipboard (as &dec)'
+      OnClick = value_viewer_context_copyClick
+    end
+    object value_viewer_context_copyasfloat: TMenuItem
+      Caption = 'Copy to clipboard (as &float)'
+      OnClick = value_viewer_context_copyClick
+    end
+    object value_viewer_context_copyasbitset: TMenuItem
+      Caption = 'Copy to clipboard (as &bitset)'
+      OnClick = value_viewer_context_copyClick
+    end
+    object value_viewer_context_copyasstring: TMenuItem
+      Caption = 'Copy to clipboard (as &string)'
+      OnClick = value_viewer_context_copyClick
+    end
+    object value_viewer_context_copyashex: TMenuItem
+      Caption = 'Copy to clipboard (as &hex)'
+      OnClick = value_viewer_context_copyClick
+    end
+  end
+end
Index: /oup/releases/0.23a/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.23a/Unit8_binedit.pas	(revision 23)
+++ /oup/releases/0.23a/Unit8_binedit.pas	(revision 23)
@@ -0,0 +1,698 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls, Clipbrd,
+  Unit3_data, Unit2_functions, Unit9_data_structures, Unit4_exporters, Menus;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    Bevel1: TBevel;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    value_viewer: TWrapGrid;
+    Splitter3: TSplitter;
+    value_viewer_context: TPopupMenu;
+    value_viewer_context_copy: TMenuItem;
+    value_viewer_context_copyashex: TMenuItem;
+    value_viewer_context_copyasdec: TMenuItem;
+    value_viewer_context_copyasfloat: TMenuItem;
+    value_viewer_context_copyasbitset: TMenuItem;
+    value_viewer_context_copyasstring: TMenuItem;
+    check_zerobyte: TCheckBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    procedure value_viewerDblClick(Sender: TObject);
+    procedure structsDblClick(Sender: TObject);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE check_zerobyteClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE value_viewer_context_copyClick(Sender: TObject);
+    PROCEDURE value_viewerMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+    PROCEDURE value_viewer_contextPopup(Sender: TObject);
+    PROCEDURE FormActivate(Sender: TObject);
+    PROCEDURE btn_importClick(Sender: TObject);
+    PROCEDURE btn_exportClick(Sender: TObject);
+    PROCEDURE panel_imexportResize(Sender: TObject);
+    FUNCTION Save:Boolean;
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    FUNCTION GetValue(datatype:Word; offset:LongWord):String;
+    PROCEDURE WriteStructureInfos(structinfoid:Integer);
+    PROCEDURE hexSelectionChanged(Sender: TObject);
+    PROCEDURE hexChange(Sender: TObject);
+    PROCEDURE panel_dataResize(Sender: TObject);
+    PROCEDURE structsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE ClearStructViewer;
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE ClearValues;
+    PROCEDURE WriteValues;
+    PROCEDURE SetNewValue(datatype:Word; offset:LongWord; value:String);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+
+
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=GetExtensionsList;
+    FOR i:=0 TO High(exts) DO
+      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm8.LoadFileNames;
+  VAR
+    Extension:String[4];
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    no_zero_bytes:=NOT check_zerobyte.Checked;
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN Extension:='';
+
+    files:=GetFilesList(extension,pattern,no_zero_bytes);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  END;
+
+PROCEDURE TForm8.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm8.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.check_zerobyteClick(Sender: TObject);
+  VAR
+    i:Byte;
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF StrToInt(MidStr(list.Items.Strings[i],1,5))=fileid THEN BEGIN
+            list.ItemIndex:=i;
+            Exit;
+          END;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
+    data:=LoadDatFile(fileid);
+    IF Length(data)>0 THEN BEGIN
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(0,soFromBeginning);
+      hex.LoadFromStream(mem);
+      mem.Free;
+      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+
+
+
+FUNCTION IntToBin(value:Byte):String;
+  VAR i:Byte;
+  BEGIN
+    Result:='';
+    FOR i:=7 DOWNTO 0 DO BEGIN
+      Result:=Result+IntToStr((value SHR i) AND $01);
+    END;
+  END;
+
+FUNCTION TForm8.GetValue(datatype:Word; offset:LongWord):String;
+  VAR
+    data:Tdata;
+    i:Word;
+  BEGIN
+    CASE datatype OF
+      1: Result:=IntToStr(hex.data[offset]);
+      2: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256);
+      3: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256);
+      4: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256);
+      5: Result:='0x'+IntToHex(hex.data[offset],2);
+      6: Result:='0x'+IntToHex(hex.data[offset]+hex.data[offset+1]*256,4);
+      7: Result:='0x'+IntToHex(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256,6);
+      8: Result:='0x'+IntToHex(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256,8);
+      9: BEGIN
+          SetLength(data,4);
+          data[0]:=hex.data[offset];
+          data[1]:=hex.data[offset+1];
+          data[2]:=hex.data[offset+2];
+          data[3]:=hex.data[offset+3];
+          Result:=FloatToStr(Decode_Float(data));
+        END;
+      10: Result:=IntToBin(hex.data[offset]);
+      10000..65535: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-10000 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Result:=Result+'.';
+          END;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm8.WriteStructureInfos(structinfoid:Integer);
+  VAR
+    i:Byte;
+  BEGIN
+    IF structinfoid>=0 THEN BEGIN
+      structs.Enabled:=True;
+      WITH structure_infos[structinfoid] DO BEGIN
+        Self.structs.RowCount:=Length(entries)+1;
+        FOR i:=1 TO Length(entries) DO BEGIN
+          Self.structs.Cells[0,i]:=entries[i-1].name;
+          Self.structs.Cells[1,i]:='0x'+IntToHex(entries[i-1].offset,6);
+          Self.structs.Cells[2,i]:=GetDataType(entries[i-1].datatype);
+          IF entries[i-1].datatype>10000 THEN
+            Self.structs.Cells[3,i]:='*String*#HINT:'+GetValue(entries[i-1].datatype,entries[i-1].offset)+'#'
+          ELSE
+            Self.structs.Cells[3,i]:=GetValue(entries[i-1].datatype,entries[i-1].offset);
+          Self.structs.Cells[4,i]:=entries[i-1].description;
+        END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm8.WriteValues;
+  VAR
+    i,j:Byte;
+    data:Tdata;
+    str:String;
+    value:LongWord;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      IF value_viewer.Cells[0,i]='1 byte, unsigned' THEN BEGIN
+        IF ((hex.SelCount=1) OR (hex.SelCount=0)) AND NOT ((hex.SelStart+1)>hex.DataSize) THEN BEGIN
+          value:=hex.Data[hex.SelStart];
+          value_viewer.Cells[1,i]:=IntToStr( value )+' / 0x'+IntToHex( value , 2 );
+        END ELSE
+          value_viewer.Cells[1,i]:='';
+      END;
+      IF value_viewer.Cells[0,i]='2 bytes, unsigned' THEN BEGIN
+        IF ((hex.SelCount=2) OR (hex.SelCount=0)) AND NOT ((hex.SelStart+2)>hex.DataSize) THEN BEGIN
+          value:=hex.Data[hex.SelStart] + hex.Data[hex.SelStart+1]*256;
+          value_viewer.Cells[1,i]:=IntToStr( value )+' / 0x'+IntToHex( value , 4 );
+        END ELSE
+          value_viewer.Cells[1,i]:='';
+      END;
+      IF value_viewer.Cells[0,i]='4 bytes, unsigned' THEN BEGIN
+        IF ((hex.SelCount=4) OR (hex.SelCount=0)) AND NOT ((hex.SelStart+4)>hex.DataSize) THEN BEGIN
+          value:=hex.Data[hex.SelStart]+hex.Data[hex.SelStart+1]*256+hex.Data[hex.SelStart+2]*256*256+hex.Data[hex.SelStart+3]*256*256*256;
+          value_viewer.Cells[1,i]:=IntToStr( value )+' / 0x'+IntToHex( value , 8 );
+        END ELSE
+          value_viewer.Cells[1,i]:='';
+      END;
+      IF value_viewer.Cells[0,i]='Bitset' THEN BEGIN
+        IF (hex.SelCount<=8) THEN BEGIN
+          IF hex.SelCount=0 THEN BEGIN
+            SetLength(data,1);
+            data[0]:=hex.Data[hex.SelStart];
+          END ELSE BEGIN
+            SetLength(data,hex.SelCount);
+            FOR j:=0 TO hex.SelCount-1 DO
+              data[j]:=hex.Data[hex.SelStart+j];
+          END;
+          value_viewer.Cells[1,i]:=DataToBin(data);
+        END ELSE
+          value_viewer.Cells[1,i]:='';
+      END;
+      IF value_viewer.Cells[0,i]='Float' THEN BEGIN
+        IF ((hex.SelCount=4) OR (hex.SelCount=0)) AND NOT ((hex.SelStart+4)>hex.DataSize) THEN BEGIN
+          SetLength(data,4);
+          FOR j:=0 TO 3 DO
+            data[j]:=hex.Data[hex.SelStart+j];
+          value_viewer.Cells[1,i]:=FloatToStr(Decode_Float(data));
+        END ELSE
+          value_viewer.Cells[1,i]:='';
+      END;
+      IF value_viewer.Cells[0,i]='Selected length' THEN BEGIN
+        value_viewer.Cells[1,i]:=IntToStr(hex.SelCount)+' bytes';
+      END;
+      IF value_viewer.Cells[0,i]='String' THEN BEGIN
+        j:=0;
+        str:='';
+        IF hex.SelCount=0 THEN BEGIN
+          WHILE (hex.Data[hex.SelStart+j]>0) AND ((hex.SelStart+j)<hex.DataSize) DO BEGIN
+            str:=str+Char(hex.Data[hex.SelStart+j]);
+            Inc(j);
+          END;
+        END ELSE BEGIN
+          FOR j:=1 TO hex.SelCount DO
+            str:=str+Char(hex.Data[hex.SelStart+j-1]);
+        END;
+        value_viewer.Cells[1,i]:=str;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    structs.Height:=40;
+    structs.ColCount:=5;
+    structs.RowCount:=2;
+    structs.FixedRows:=1;
+    structs.Cells[0,0]:='Name';
+    structs.Cells[1,0]:='Offset';
+    structs.Cells[2,0]:='Type';
+    structs.Cells[3,0]:='Value';
+    structs.Cells[4,0]:='Description';
+    structs.ColWidths[0]:=75;
+    structs.ColWidths[1]:=60;
+    structs.ColWidths[2]:=75;
+    structs.ColWidths[3]:=75;
+    value_viewer.ColCount:=2;
+    value_viewer.RowCount:=8;
+    value_viewer.FixedRows:=1;
+    value_viewer.Cells[0,0]:='Type';
+    value_viewer.Cells[1,0]:='Value';
+    value_viewer.Cells[0,1]:='1 byte, unsigned';
+    value_viewer.Cells[0,2]:='2 bytes, unsigned';
+    value_viewer.Cells[0,3]:='4 bytes, unsigned';
+    value_viewer.Cells[0,4]:='Bitset';
+    value_viewer.Cells[0,5]:='Float';
+    value_viewer.Cells[0,6]:='String';
+    value_viewer.Cells[0,7]:='Selected length';
+    value_viewer.ColWidths[0]:=100;
+    hex.Height:=panel_data.Height-215;
+    Self.panel_dataResize(Self);
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+GetFileInfo(fileid).FileName+'?'),PChar('Data changed...'),MB_YESNOCANCEL) OF
+      IDYES: BEGIN
+          mem:=TMemoryStream.Create;
+          hex.SaveToStream(mem);
+          mem.Seek(0,soFromBeginning);
+          SetLength(data,mem.Size);
+          mem.Read(data[0],mem.Size);
+          mem.Free;
+          UpdateDatFile(fileid,data);
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm8.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm8.ClearStructViewer;
+  VAR
+    x:Word;
+  BEGIN
+    structs.RowCount:=2;
+    FOR x:=0 TO structs.ColCount-1 DO structs.Cells[x,1]:='';
+    structs.Enabled:=False;
+    structs.Height:=40;
+  END;
+
+PROCEDURE TForm8.FormResize(Sender: TObject);
+  BEGIN
+    IF Self.Width>=650 THEN BEGIN
+    END ELSE Self.Width:=650;
+    IF Self.Height>=450 THEN BEGIN
+    END ELSE Self.Height:=450;
+  END;
+
+PROCEDURE TForm8.structsClick(Sender: TObject);
+  VAR
+    offset:LongWord;
+    length:Byte;
+  BEGIN
+    IF structs.Row>0 THEN BEGIN
+      offset:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].offset;
+      length:=GetTypeDataLength(structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].datatype);
+      hex.SelStart:=offset;
+      hex.SelEnd:=offset+length-1;
+    END;
+  END;
+
+PROCEDURE TForm8.panel_dataResize(Sender: TObject);
+  BEGIN
+    structs.ColWidths[4]:=structs.Width-structs.ColWidths[0]-structs.ColWidths[1]-structs.ColWidths[2]-structs.ColWidths[3]-28;
+    value_viewer.ColWidths[1]:=value_viewer.Width-value_viewer.ColWidths[0]-28;
+  END;
+
+PROCEDURE TForm8.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm8.hexSelectionChanged(Sender: TObject);
+  VAR
+    selstart:Integer;
+    i,j:Word;
+  BEGIN
+    FOR i:=1 TO structs.RowCount-1 DO BEGIN
+      FOR j:=0 TO structs.ColCount-1 DO BEGIN
+        structs.CellColors[j,i]:=clWhite;
+        structs.CellFontColors[j,i]:=clBlack;
+      END;
+    END;
+    IF hex.DataSize>0 THEN BEGIN
+      selstart:=hex.SelStart;
+      IF GetStructureInfoId(GetFileInfo(fileid).Extension)>=0 THEN BEGIN
+        WITH structure_infos[GetStructureInfoId(GetFileInfo(fileid).Extension)] DO BEGIN
+          FOR i:=0 TO High(entries) DO BEGIN
+            IF ((selstart-entries[i].offset)<GetTypeDataLength(entries[i].datatype)) AND ((selstart-entries[i].offset)>=0) THEN BEGIN
+              FOR j:=0 TO structs.ColCount-1 DO BEGIN
+                structs.CellColors[j,i+1]:=clBlue;
+                structs.CellFontColors[j,i+1]:=clWhite;
+              END;
+              structs.Row:=i+1;
+            END;
+          END;
+        END;
+      END;
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm8.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm8.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm8.btn_exportClick(Sender: TObject);
+  BEGIN
+    saved.Filter:='Files of matching extension (*.'+GetFileInfo(fileid).Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    saved.DefaultExt:=GetFileInfo(fileid).Extension;
+    IF saved.Execute THEN BEGIN
+      ExportDatFile(fileid,saved.FileName);
+    END;
+  END;
+
+PROCEDURE TForm8.btn_importClick(Sender: TObject);
+  VAR
+    data:Tdata;
+    fs:TFileStream;
+  BEGIN
+    opend.Filter:='Files of matching extension (*.'+GetFileInfo(fileid).Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    IF opend.Execute THEN BEGIN
+      fs:=TFileStream.Create(opend.FileName,fmOpenRead);
+      IF fs.Size<>hex.DataSize THEN BEGIN
+        ShowMessage('Can''t import '+ExtractFilename(opend.FileName)+
+                    ', file has to have same size as file in .dat.'+CrLf+
+                    'Size of file in .dat: '+FormatFileSize(hex.datasize)+CrLf+
+                    'Size of chosen file: '+FormatFileSize(fs.Size));
+      END ELSE BEGIN
+        hex.LoadFromStream(fs);
+        hex.Modified:=True;
+      END;
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm8.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm8.value_viewer_contextPopup(Sender: TObject);
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=0 TO value_viewer_context.Items.Count-1 DO
+      value_viewer_context.Items.Items[i].Visible:=False;
+    WITH value_viewer DO BEGIN
+      IF (Col=1) AND (Row>0) AND (Length(Cells[Col,Row])>0) THEN BEGIN
+        IF Pos(' byte',Cells[0,Row])=2 THEN BEGIN
+          value_viewer_context.Items.Find('Copy to &clipboard').Visible:=True;
+          value_viewer_context.Items.Find('Copy to clipboard (as &dec)').Visible:=True;
+          value_viewer_context.Items.Find('Copy to clipboard (as &hex)').Visible:=True;
+        END;
+        IF Pos('Float',Cells[0,Row])=1 THEN
+          value_viewer_context.Items.Find('Copy to clipboard (as &float)').Visible:=True;
+        IF Pos('Bitset',Cells[0,Row])=1 THEN
+          value_viewer_context.Items.Find('Copy to clipboard (as &bitset)').Visible:=True;
+        IF Pos('String',Cells[0,Row])=1 THEN
+          value_viewer_context.Items.Find('Copy to clipboard (as &string)').Visible:=True;
+        IF Pos('Selected length',Cells[0,Row])=1 THEN
+          value_viewer_context.Items.Find('Copy to &clipboard').Visible:=True;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.value_viewerMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
+  VAR
+    ACol,ARow:Integer;
+  BEGIN
+    IF Button=mbRight THEN BEGIN
+      value_viewer.MouseToCell(x,y,ACol,ARow);
+      IF ARow>0 THEN BEGIN
+        value_viewer.Col:=ACol;
+        value_viewer.Row:=ARow;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.value_viewer_context_copyClick(Sender: TObject);
+  VAR
+    i:Byte;
+    name:String;
+    value:LongWord;
+  BEGIN
+    name:=TMenuItem(Sender).Name;
+    IF Pos('asstring',name)>0 THEN BEGIN
+      Clipboard.AsText:=value_viewer.Cells[value_viewer.Col,value_viewer.Row];
+    END ELSE
+    IF Pos('asfloat',name)>0 THEN BEGIN
+      Clipboard.AsText:=value_viewer.Cells[value_viewer.Col,value_viewer.Row];
+    END ELSE
+    IF Pos('asbitset',name)>0 THEN BEGIN
+      Clipboard.AsText:=value_viewer.Cells[value_viewer.Col,value_viewer.Row];
+    END ELSE
+    IF (Pos('ashex',name)>0) OR (Pos('asdec',name)>0) THEN BEGIN
+      IF value_viewer.Cells[0,value_viewer.Row]='1 byte, unsigned' THEN BEGIN
+        IF ((hex.SelCount=1) OR (hex.SelCount=0)) AND NOT ((hex.SelStart+1)>hex.DataSize) THEN
+          value:=hex.Data[hex.SelStart];
+      END;
+      IF value_viewer.Cells[0,value_viewer.Row]='2 bytes, unsigned' THEN BEGIN
+        IF ((hex.SelCount=2) OR (hex.SelCount=0)) AND NOT ((hex.SelStart+2)>hex.DataSize) THEN
+          value:=hex.Data[hex.SelStart] + hex.Data[hex.SelStart+1]*256;
+      END;
+      IF value_viewer.Cells[0,value_viewer.Row]='4 bytes, unsigned' THEN BEGIN
+        IF ((hex.SelCount=4) OR (hex.SelCount=0)) AND NOT ((hex.SelStart+4)>hex.DataSize) THEN
+          value:=hex.Data[hex.SelStart]+hex.Data[hex.SelStart+1]*256+hex.Data[hex.SelStart+2]*256*256+hex.Data[hex.SelStart+3]*256*256*256;
+      END;
+      IF Pos('asdec',name)>0 THEN BEGIN
+        Clipboard.AsText:=IntToStr(value);
+      END ELSE BEGIN
+        IF value_viewer.Cells[0,value_viewer.Row]='1 byte, unsigned' THEN
+          Clipboard.AsText:='0x'+IntToHex(value,2);
+        IF value_viewer.Cells[0,value_viewer.Row]='2 bytes, unsigned' THEN
+          Clipboard.AsText:='0x'+IntToHex(value,4);
+        IF value_viewer.Cells[0,value_viewer.Row]='4 bytes, unsigned' THEN
+          Clipboard.AsText:='0x'+IntToHex(value,8);
+      END;
+    END ELSE BEGIN
+      Clipboard.AsText:=value_viewer.Cells[value_viewer.Col,value_viewer.Row];
+    END;
+  END;
+
+PROCEDURE TForm8.structsDblClick(Sender: TObject);
+  VAR
+    offset:LongWord;
+    datatype:Word;
+    objectname:String;
+    value:String;
+  BEGIN
+    IF (structs.Row>0) AND (structs.Cells[structs.Col,0]='Value') THEN BEGIN
+      offset:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].offset;
+      datatype:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].datatype;
+      objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+      value:=GetValue(datatype,offset);
+      Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+    END;
+  END;
+
+PROCEDURE TForm8.SetNewValue(datatype:Word; offset:LongWord; value:String);
+  VAR
+    data:Tdata;
+    value_int:LongWord;
+    value_float:Single;
+    i:Word;
+  BEGIN
+    CASE datatype OF
+      1..4: BEGIN
+              value_int:=StrToInt(value);
+              SetLength(data,datatype);
+              FOR i:=0 TO datatype-1 DO BEGIN
+                data[i]:=value_int MOD 256;
+                value_int:=value_int DIV 256;
+              END;
+            END;
+      5..8: BEGIN
+              value_int:=StrToInt('$'+value);
+              SetLength(data,datatype-4);
+              FOR i:=0 TO datatype-5 DO BEGIN
+                data[i]:=value_int MOD 256;
+                value_int:=value_int DIV 256;
+              END;
+            END;
+      9:    BEGIN
+              value_float:=StrToFloat(value);
+              data:=Encode_Float(value_float);
+            END;
+      10:   BEGIN
+              value_int:=BinToInt(value);
+              SetLength(data,1);
+              data[0]:=value_int;
+            END;
+      10000..65535: BEGIN
+              SetLength(data,datatype-10000);
+              FOR i:=1 TO datatype-10000 DO BEGIN
+                IF i<=Length(value) THEN
+                  data[i-1]:=Ord(value[i])
+                ELSE
+                  data[i-1]:=0;
+              END;
+            END;
+    END;
+    FOR i:=0 TO High(data) DO BEGIN
+      IF hex.Data[offset+i]<>data[i] THEN hex.ByteChanged[offset+i]:=True;
+      hex.Data[offset+i]:=data[i];
+    END;
+    hex.Modified:=True;
+    hexChange(Self);
+    hex.Repaint;
+  END;
+
+PROCEDURE TForm8.value_viewerDblClick(Sender: TObject);
+  VAR
+    offset:LongWord;
+    datatype:Word;
+    objectname:String;
+    value:String;
+  BEGIN
+    IF (value_viewer.Col=1) AND (Length(value_viewer.Cells[1,value_viewer.Row])>0) THEN BEGIN
+      offset:=hex.SelStart;
+      IF value_viewer.Cells[0,value_viewer.Row]='1 byte, unsigned' THEN
+        datatype:=1;
+      IF value_viewer.Cells[0,value_viewer.Row]='2 bytes, unsigned' THEN
+        datatype:=2;
+      IF value_viewer.Cells[0,value_viewer.Row]='4 bytes, unsigned' THEN
+        datatype:=4;
+      IF value_viewer.Cells[0,value_viewer.Row]='Bitset' THEN
+        datatype:=10;
+      IF value_viewer.Cells[0,value_viewer.Row]='Float' THEN
+        datatype:=9;
+      IF value_viewer.Cells[0,value_viewer.Row]='Selected length' THEN
+        Exit;
+      IF value_viewer.Cells[0,value_viewer.Row]='String' THEN BEGIN
+        IF hex.SelCount>0 THEN
+          datatype:=10000+hex.SelCount
+        ELSE
+          datatype:=10000+Length(value_viewer.Cells[1,value_viewer.Row]);
+      END;
+      objectname:='';
+      value:=GetValue(datatype,offset);
+      Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+    END;
+  END;
+
+END.
Index: /oup/releases/0.23a/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.23a/Unit9_data_structures.pas	(revision 23)
+++ /oup/releases/0.23a/Unit9_data_structures.pas	(revision 23)
@@ -0,0 +1,113 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils;
+
+TYPE
+  Tstructure_entry=RECORD
+      name:String;
+      offset:LongWord;
+      datatype:Word;  // 1..4: Integer[1..4] dec; 5..8: Integer[1..4] hex; 9: float; 10: bitset; 10000+: string[0+]
+      description:String;
+    END;
+  Tstructure_info=RECORD
+      extension:String;
+      typedesc:String;
+      entries:Array OF Tstructure_entry;
+    END;
+  Tstructures=Array OF Tstructure_info;
+
+VAR
+  structure_infos:Tstructures;
+
+
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+
+
+
+IMPLEMENTATION
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      10000..65535: Result:=datatype-10000;
+    END;
+  END;
+
+
+FUNCTION GetStructureInfoId(ext:String):Integer;
+  VAR
+    i:Integer;
+  BEGIN
+    FOR i:=0 TO High(structure_infos) DO BEGIN
+      IF structure_infos[i].extension=ext THEN BEGIN
+        Result:=i;
+        Exit;
+      END;
+    END;
+    Result:=-1;
+  END;
+
+
+FUNCTION GetDataType(typeid:Word):String;
+  BEGIN
+    CASE typeid OF
+      1..4: Result:='Int'+IntToStr(typeid*8);
+      5..8: Result:='Int'+IntToStr((typeid-4)*8);
+      9: Result:='Float';
+      10: Result:='BitSet';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+PROCEDURE AddEntry(_ext:String; _name:String; _offset:LongWord; _datatype:Word; _description:String);
+  VAR
+    sid:Integer;
+  BEGIN
+    sid:=GetStructureInfoId(_ext);
+    IF sid>=0 THEN BEGIN
+      WITH structure_infos[sid] DO BEGIN
+        SetLength(entries,Length(entries)+1);
+        WITH entries[High(entries)] DO BEGIN
+          name:=_name;
+          offset:=_offset;
+          datatype:=_datatype;
+          description:=_description;
+        END;
+      END;
+    END;
+  END;
+
+
+PROCEDURE AddExtension(_ext:String; _typedesc:String);
+  BEGIN
+    IF GetStructureInfoId(_ext)<0 THEN BEGIN
+      SetLength(structure_infos,Length(structure_infos)+1);
+      WITH structure_infos[High(structure_infos)] DO BEGIN
+        extension:=_ext;
+        typedesc:=_typedesc;
+      END;
+    END;
+  END;
+
+
+BEGIN
+  AddExtension('TXMP','Texture');
+  AddEntry('TXMP','ID',$00,4,'ID of this file');
+  AddEntry('TXMP','LevelID',$04,8,'ID of the level this file is in');
+  AddEntry('TXMP','FileName',$08,10128,'');
+  AddEntry('TXMP','Fading',$88,10,'Fading-Bitset');
+  AddEntry('TXMP','Depth',$89,10,'Depth-Bitset');
+  AddEntry('TXMP','Width',$8C,2,'x-resolution of image');
+  AddEntry('TXMP','Height',$8E,2,'y-resolution of image');
+  AddEntry('TXMP','Storetype',$90,10,'Storetype-Bitset');
+  AddEntry('TXMP','TXAN-Link',$94,8,'Link to the TXAN-file (if this TXMP is the first image of an animation)');
+  AddEntry('TXMP','TXMP-Link',$98,8,'Link to another TXMP-file');
+  AddEntry('TXMP','Raw-Link',$9C,8,'Address of the image data in the .raw-file');
+END.
