Index: /oup/releases/0.11a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.11a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.11a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.11a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.11a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.11a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,11 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.11a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.11a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.11a/src/OniUnPacker.cfg	(revision 8)
@@ -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.11a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.11a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.11a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,19 @@
+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';
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm5, Form5);
+  Application.Run;
+END.
Index: /oup/releases/0.11a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.11a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.11a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,295 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 454
+  ClientWidth = 742
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = menu
+  OldCreateOrder = False
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_all: TPanel
+    Left = 0
+    Top = 100
+    Width = 692
+    Height = 300
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter2: TSplitter
+      Left = 360
+      Top = 0
+      Width = 8
+      Height = 300
+      AutoSnap = False
+      Beveled = True
+      MinSize = 360
+      OnMoved = Splitter2Moved
+    end
+    object panel_left: TPanel
+      Left = 0
+      Top = 0
+      Width = 360
+      Height = 300
+      Cursor = crDrag
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object Splitter1: TSplitter
+        Left = 0
+        Top = 241
+        Width = 360
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+        OnMoved = Splitter1Moved
+      end
+      object panel_files: TPanel
+        Left = 0
+        Top = 0
+        Width = 360
+        Height = 241
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_extractallconvert: TButton
+          Left = 273
+          Top = 208
+          Width = 82
+          Height = 33
+          Caption = 'Extract all (with convert)'
+          TabOrder = 0
+          WordWrap = True
+          OnClick = btn_extractallconvertClick
+        end
+        object btn_extract: TButton
+          Left = 0
+          Top = 208
+          Width = 100
+          Height = 33
+          Caption = 'Extract file (without convert)'
+          TabOrder = 1
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object btn_extractconvert: TButton
+          Left = 101
+          Top = 208
+          Width = 105
+          Height = 33
+          Caption = 'Extract file (with convert if possible)'
+          TabOrder = 2
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object list_files: TListBox
+          Left = 0
+          Top = 0
+          Width = 360
+          Height = 209
+          Align = alTop
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Fixedsys'
+          Font.Style = []
+          ItemHeight = 15
+          ParentFont = False
+          TabOrder = 3
+          OnClick = list_filesDblClick
+          OnDblClick = list_filesDblClick
+        end
+        object btn_extractall: TButton
+          Left = 210
+          Top = 208
+          Width = 62
+          Height = 33
+          Caption = 'Extract all'
+          TabOrder = 4
+          WordWrap = True
+          OnClick = btn_extractallconvertClick
+        end
+      end
+      object list_extensions: TListBox
+        Left = 0
+        Top = 249
+        Width = 360
+        Height = 51
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+        OnClick = list_extensionsClick
+        OnDblClick = list_extensionsClick
+      end
+    end
+    object panel_right: TPanel
+      Left = 368
+      Top = 0
+      Width = 324
+      Height = 300
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 1
+      object Splitter3: TSplitter
+        Left = 0
+        Top = 200
+        Width = 324
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+      end
+      object edit_data: TMemo
+        Left = 0
+        Top = 0
+        Width = 324
+        Height = 200
+        Align = alTop
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -13
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ParentFont = False
+        ReadOnly = True
+        ScrollBars = ssVertical
+        TabOrder = 0
+        WordWrap = False
+      end
+      object list_names: TListBox
+        Left = 0
+        Top = 208
+        Width = 324
+        Height = 92
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+      end
+    end
+  end
+  object panel_info: TPanel
+    Left = 0
+    Top = 0
+    Width = 742
+    Height = 100
+    Align = alTop
+    BevelOuter = bvNone
+    TabOrder = 1
+    object lbl_info: TLabel
+      Left = 2
+      Top = 26
+      Width = 345
+      Height = 73
+      AutoSize = False
+      Caption = 'lbl_info'
+    end
+    object lbl_fileinfo: TLabel
+      Left = 380
+      Top = 0
+      Width = 345
+      Height = 99
+      AutoSize = False
+      Caption = 'lbl_fileinfo'
+    end
+    object btn_load: TButton
+      Left = 0
+      Top = 0
+      Width = 81
+      Height = 25
+      Caption = 'Load dat-file'
+      TabOrder = 0
+      OnClick = btn_loadClick
+    end
+    object btn_hexcopy: TButton
+      Left = 295
+      Top = 64
+      Width = 89
+      Height = 33
+      Caption = 'Copy filedata as hex to clipboard'
+      TabOrder = 1
+      WordWrap = True
+      OnClick = btn_hexcopyClick
+    end
+  end
+  object group_progress: TGroupBox
+    Left = 160
+    Top = 384
+    Width = 297
+    Height = 57
+    Caption = 'Extracting...'
+    TabOrder = 2
+    Visible = False
+    object lbl_progress: TLabel
+      Left = 10
+      Top = 36
+      Width = 279
+      Height = 18
+      AutoSize = False
+    end
+    object progress: TProgressBar
+      Left = 8
+      Top = 16
+      Width = 217
+      Height = 17
+      Step = 1
+      TabOrder = 0
+    end
+    object btn_extractcancel: TButton
+      Left = 232
+      Top = 16
+      Width = 57
+      Height = 33
+      Caption = 'Cancel'
+      TabOrder = 1
+      OnClick = btn_extractcancelClick
+    end
+  end
+  object fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    Left = 72
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 128
+    object menu_main: TMenuItem
+      Caption = 'Main'
+      object menu_exit: TMenuItem
+        Caption = 'Exit'
+      end
+    end
+    object menu_preview: TMenuItem
+      Caption = 'Preview Window'
+      OnClick = menu_previewClick
+    end
+  end
+end
Index: /oup/releases/0.11a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.11a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.11a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,370 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview;
+
+TYPE
+  TForm1 = Class(TForm)
+    panel_all: TPanel;
+    panel_left: TPanel;
+    Splitter1: TSplitter;
+    panel_files: TPanel;
+    btn_extractallconvert: TButton;
+    btn_extract: TButton;
+    btn_extractconvert: TButton;
+    list_files: TListBox;
+    btn_extractall: TButton;
+    list_extensions: TListBox;
+    Splitter2: TSplitter;
+    panel_right: TPanel;
+    edit_data: TMemo;
+    list_names: TListBox;
+    Splitter3: TSplitter;
+    panel_info: TPanel;
+    lbl_info: TLabel;
+    btn_load: TButton;
+    btn_hexcopy: TButton;
+    fopen: TOpenDialog;
+    lbl_fileinfo: TLabel;
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    btn_extractcancel: TButton;
+    procedure btn_extractcancelClick(Sender: TObject);
+    PROCEDURE menu_previewClick(Sender: TObject);
+    PROCEDURE btn_extractallconvertClick(Sender: TObject);
+    PROCEDURE Splitter2Moved(Sender: TObject);
+    PROCEDURE Splitter1Moved(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE btn_hexcopyClick(Sender: TObject);
+    PROCEDURE list_extensionsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE btn_extractconvertClick(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE list_filesDblClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form1: TForm1;
+
+IMPLEMENTATION
+{$R *.dfm}
+
+PROCEDURE DoAfterLoadOfADat;
+  VAR
+    i:LongWord;
+    txt:Text;
+    temp4:LongWord;
+    temp2:Word;
+    temp1:Byte;
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='M') AND
+          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXMP' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$88,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$89,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$8C,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$8E,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$90,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='A') AND
+          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXAN' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$14,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$16,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$1C,4,@temp4);
+        Write(txt,IntToHex(temp4,8)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+  END;
+
+PROCEDURE TForm1.btn_loadClick(Sender: TObject);
+  VAR i:LongWord;
+  BEGIN
+    fopen.InitialDir:=AppSettings.DatPath;
+    IF fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(fopen.FileName);
+      list_files.Items.Clear;
+      list_extensions.Items.Clear;
+      list_names.Items.Clear;
+      IF LoadDatInfos(fopen.FileName) THEN BEGIN
+        lbl_info.Caption:=
+              '# of files: '+IntToStr(dat_header.Files)+CrLf+
+              '# of named files: '+IntToStr(dat_header.NamedFiles)+CrLf+
+              '# of extensions: '+IntToStr(dat_header.Extensions)+CrLf+
+              'Address of Body: 0x'+IntToHex(dat_header.DataAddr,8)+CrLf+
+              'Address of End: 0x'+IntToHex(dat_header.NamesAddr,8);
+        list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
+        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+          WITH dat_extensionsmap[i] DO BEGIN
+            list_extensions.Items.Add(
+                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
+                FormatNumber(ExtCount,4,' ')+' (Ident: 0x'+
+                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');
+          END;
+        END;
+        FOR i:=0 TO dat_header.namedFiles-1 DO BEGIN
+          WITH dat_namedfilesmap[i] DO BEGIN
+            list_names.Items.Add('0x'+IntToHex(filenumber,8)+': 0x'+IntToHex(blubb,8));
+          END;
+        END;
+        Form1.list_extensions.ItemIndex:=0;
+        Form1.list_extensionsClick(Form1);
+        Form1.list_files.ItemIndex:=0;
+        Form1.list_filesDblClick(Form1);
+
+        DoAfterLoadOfADat;
+
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    temp:Tdata;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    lbl_fileinfo.Caption:=
+          'Filename: '+dat_files[id].FileName+CrLf+
+          'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
+          'FileType: 0x'+IntToHex(dat_files[id].FileType,8)+CrLf+
+          'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
+    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
+      temp:=LoadDatFile(id);
+      edit_data.Text:=CreateHexString(temp,False);
+      btn_hexcopy.Visible:=True;
+      IF menu_preview.Checked THEN Form5.ShowPreview(id); 
+    END ELSE BEGIN
+      edit_data.Text:='Zero byte file.'+CrLf+'Oni will take the data for this file of level0_final.dat/raw';
+      btn_hexcopy.Visible:=False;
+    END;
+  END;
+
+PROCEDURE TForm1.FormCreate(Sender: TObject);
+  BEGIN
+    Form1.Caption:='Oni Un/Packer '+version;
+    Form1.FormResize(Form1);
+
+    panel_all.Align:=alClient;
+
+    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;
+
+    Form1.btn_loadClick(Form1);
+  END;
+
+PROCEDURE TForm1.btn_extractconvertClick(Sender: TObject);
+  VAR
+    result:Integer;
+    id:LongWord;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    IF TComponent(Sender).Name='btn_extract' THEN
+      result:=ExportFile(id,False)
+    ELSE
+      result:=ExportFile(id,True);
+    CASE result OF
+      0{export_noerror}: IF 1=2 THEN BEGIN END;
+      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
+      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
+      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
+    ELSE ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
+    END;
+    Form1.list_files.SetFocus;
+  END;
+
+PROCEDURE TForm1.FormResize(Sender: TObject);
+  CONST
+    MinWidth:Integer=750;
+    MinHeight:Integer=500;
+  BEGIN
+    IF NOT group_progress.Visible THEN BEGIN
+      IF Form1.Width<MinWidth THEN Form1.Width:=MinWidth;
+      IF Form1.Height<MinHeight THEN Form1.Height:=MinHeight;
+    END;
+  END;
+
+PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
+    list_files.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        list_files.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          list_files.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
+  VAR
+    temp:Tdata;
+  BEGIN
+    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
+    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
+  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);
+  END;
+
+PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
+  BEGIN
+    Form1.list_files.Height:=Form1.Splitter1.Top-32;
+    Form1.btn_extractallconvert.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extract.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extractall.Top:=Form1.Splitter1.Top-33;
+  END;
+
+PROCEDURE TForm1.Splitter2Moved(Sender: TObject);
+  BEGIN
+    Form1.btn_extractall.Left:=Form1.Splitter2.Left-146;
+    Form1.btn_extractallconvert.Left:=Form1.Splitter2.Left-83;
+  END;
+
+PROCEDURE TForm1.btn_extractallconvertClick(Sender: TObject);
+  VAR
+    convert:Boolean;
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    panel_info.Visible:=False;
+    group_progress.Visible:=True;
+    FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=103;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=dat_header.files;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    IF TComponent(Sender).Name='btn_extractall' THEN
+      convert:=False
+    ELSE
+      convert:=True;
+    errors:=0;
+    FOR i:=0 TO High(dat_files) DO BEGIN
+      IF ExportFile(i,convert)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+    panel_info.Visible:=True;
+    group_progress.Visible:=False;
+  END;
+
+PROCEDURE TForm1.menu_previewClick(Sender: TObject);
+  BEGIN
+    menu_preview.Checked:=NOT menu_preview.Checked;
+    IF menu_preview.Checked THEN BEGIN
+      Form5.Visible:=True;
+    END ELSE BEGIN
+      Form5.Visible:=False;
+    END;
+  END;
+
+PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
+  BEGIN
+    btn_extractcancel.Caption:='Cancel_';
+  END;
+
+END.
Index: /oup/releases/0.11a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.11a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.11a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,205 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, Unit3_data, Unit4_Exporters;
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    IF Length(filename)>0 THEN dat_file.Free;
+    dat_filename:=filename;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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>=1024*1024*1024 THEN BEGIN
+      Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB';
+    END ELSE BEGIN
+      IF size>=1024*1024 THEN BEGIN
+        Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB';
+      END ELSE BEGIN
+        IF size>=1024 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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.11a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.11a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.11a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,83 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.11a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  dat_filename:String='';
+  dat_header:Theader;
+  dat_filesmap:Tfilesmap;
+  dat_files:Tfiles;
+  dat_namedfilesmap:Tnamedfilesmap;
+  dat_extensionsmap:Textensionsmap;
+  AppSettings:TAppSettings;
+  AppSettingsFile:File OF TAppSettings;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.11a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.11a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.11a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,136 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..4] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (Ext:'TRAC'; needed:True; Handler:ExportTRAC),
+    (Ext:'TXAN'; needed:True; Handler:ExportTXAN),
+    (Ext:'TXMP'; needed:True; Handler:ExportTXMP)
+  );
+
+
+
+IMPLEMENTATION
+USES Unit2_functions;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DAT_'),fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.11a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.11a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.11a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,74 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 435
+  Height = 348
+  BorderStyle = bsSizeToolWin
+  Caption = 'Preview'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object img: TImage
+    Left = 0
+    Top = 20
+    Width = 427
+    Height = 304
+    Align = alClient
+  end
+  object panel_buttons: TPanel
+    Left = 0
+    Top = 0
+    Width = 427
+    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
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 72
+    Top = 48
+  end
+end
Index: /oup/releases/0.11a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.11a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.11a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,173 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    img: TImage;
+    timer: TTimer;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    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 FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE ShowPreview(fileid:LongWord);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  memstreams:Array OF TMemoryStream;
+  actualimg:Byte;
+  _fileid:LongWord;
+
+PROCEDURE PreviewTXMP;
+  VAR
+    data:Tdata;
+    img:TImgPackage;
+  BEGIN
+    {
+    tempdata:=ResizeImage(imgx,imgy,imgdepth,tempdata);
+    imgx:=imgx DIV 2;
+    imgy:=imgy DIV 2;
+    datasize:=datasize DIV 4;
+    }
+    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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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;
+    Form5.timer.Interval:=Floor(loop_speed*(1/60)*1000);
+    Form5.timer.Enabled:=False;
+    Form5.btn_startstopClick(Form5); 
+    Form5.panel_buttons.Visible:=True;
+  END;
+
+PROCEDURE TForm5.ShowPreview(fileid:LongWord);
+  BEGIN
+    _fileid:=fileid;
+    Form5.timer.Enabled:=False;
+    Form5.panel_buttons.Visible:=False;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[fileid].Extension='TXMP' THEN PreviewTXMP;
+    IF dat_files[fileid].Extension='TXAN' THEN PreviewTXAN;
+  END;
+
+PROCEDURE TForm5.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form1.menu_preview.Checked:=False;
+    Form5.Visible:=False;
+  END;
+
+PROCEDURE TForm5.FormCreate(Sender: TObject);
+  BEGIN
+    SetLength(memstreams,1);
+    memstreams[0]:=TMemoryStream.Create;
+    Form5.Width:=170;
+    Form5.Height:=200;
+  END;
+
+PROCEDURE TForm5.timerTimer(Sender: TObject);
+  BEGIN
+    Inc(actualimg);
+    IF actualimg>=Length(memstreams) THEN actualimg:=0;
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+    Form5.Caption:='Preview '+dat_files[_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
+    Form5.timer.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_dec.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_inc.Enabled:=NOT Form5.timer.Enabled;
+    IF Form5.timer.Enabled THEN
+      Form5.btn_startstop.Caption:='Stop automatic'
+    ELSE
+      Form5.btn_startstop.Caption:='Start automatic';
+  END;
+
+PROCEDURE TForm5.FormResize(Sender: TObject);
+  BEGIN
+    IF Form5.Width>=150 THEN BEGIN
+    END ELSE Form5.Width:=150;
+    IF Form5.Height>=150 THEN BEGIN
+    END ELSE Form5.Height:=150;
+  END;
+
+PROCEDURE TForm5.btn_decClick(Sender: TObject);
+  BEGIN
+    IF actualimg>0 THEN
+      Dec(actualimg)
+    ELSE
+      actualimg:=High(memstreams);
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.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;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+END.
Index: /oup/releases/0.11a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.11a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.11a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,235 @@
+UNIT Unit6_imgfuncs;
+INTERFACE
+USES Math, 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 LoadImgData(fileid:LongWord):TImgPackage;
+
+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,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]:=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;
+      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 LoadImgData(fileid:LongWord):TImgPackage;
+{  VAR
+    raw_addr:LongWord;
+    storetype:Byte;
+    imgx,imgy:Word;
+    imgdepth:Byte;
+    data:Tdata;
+    datasize:LongWord;}
+  BEGIN
+      LoadDatFilePart(fileid,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+      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);
+
+      LoadRawFilePart(Result.raw_addr,Result.datasize,@Result.imgdata[0]);
+  END;
+
+END.
Index: /oup/releases/0.12a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.12a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.12a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.12a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.12a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.12a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,11 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.12a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.12a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.12a/src/OniUnPacker.cfg	(revision 8)
@@ -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.12a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.12a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.12a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,19 @@
+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';
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm5, Form5);
+  Application.Run;
+END.
Index: /oup/releases/0.12a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.12a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.12a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,301 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 454
+  ClientWidth = 742
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = menu
+  OldCreateOrder = False
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_all: TPanel
+    Left = 0
+    Top = 100
+    Width = 692
+    Height = 300
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter2: TSplitter
+      Left = 360
+      Top = 0
+      Width = 8
+      Height = 300
+      AutoSnap = False
+      Beveled = True
+      MinSize = 360
+      OnMoved = Splitter2Moved
+    end
+    object panel_left: TPanel
+      Left = 0
+      Top = 0
+      Width = 360
+      Height = 300
+      Cursor = crDrag
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object Splitter1: TSplitter
+        Left = 0
+        Top = 241
+        Width = 360
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+        OnMoved = Splitter1Moved
+      end
+      object panel_files: TPanel
+        Left = 0
+        Top = 0
+        Width = 360
+        Height = 241
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_extractallconvert: TButton
+          Left = 273
+          Top = 208
+          Width = 82
+          Height = 33
+          Caption = 'Extract all (with convert)'
+          TabOrder = 0
+          WordWrap = True
+          OnClick = btn_extractallconvertClick
+        end
+        object btn_extract: TButton
+          Left = 0
+          Top = 208
+          Width = 100
+          Height = 33
+          Caption = 'Extract file (without convert)'
+          TabOrder = 1
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object btn_extractconvert: TButton
+          Left = 101
+          Top = 208
+          Width = 105
+          Height = 33
+          Caption = 'Extract file (with convert if possible)'
+          TabOrder = 2
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object list_files: TListBox
+          Left = 0
+          Top = 0
+          Width = 360
+          Height = 209
+          Align = alTop
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Fixedsys'
+          Font.Style = []
+          ItemHeight = 15
+          ParentFont = False
+          TabOrder = 3
+          OnClick = list_filesDblClick
+          OnDblClick = list_filesDblClick
+        end
+        object btn_extractall: TButton
+          Left = 210
+          Top = 208
+          Width = 62
+          Height = 33
+          Caption = 'Extract all'
+          TabOrder = 4
+          WordWrap = True
+          OnClick = btn_extractallconvertClick
+        end
+      end
+      object list_extensions: TListBox
+        Left = 0
+        Top = 249
+        Width = 360
+        Height = 51
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+        OnClick = list_extensionsClick
+        OnDblClick = list_extensionsClick
+      end
+    end
+    object panel_right: TPanel
+      Left = 368
+      Top = 0
+      Width = 324
+      Height = 300
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 1
+      object Splitter3: TSplitter
+        Left = 0
+        Top = 200
+        Width = 324
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+      end
+      object edit_data: TMemo
+        Left = 0
+        Top = 0
+        Width = 324
+        Height = 200
+        Align = alTop
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -13
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ParentFont = False
+        ReadOnly = True
+        ScrollBars = ssVertical
+        TabOrder = 0
+        WordWrap = False
+      end
+      object list_names: TListBox
+        Left = 0
+        Top = 208
+        Width = 324
+        Height = 92
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+      end
+    end
+  end
+  object panel_info: TPanel
+    Left = 0
+    Top = 0
+    Width = 742
+    Height = 100
+    Align = alTop
+    BevelOuter = bvNone
+    TabOrder = 1
+    object lbl_info: TLabel
+      Left = 2
+      Top = 26
+      Width = 345
+      Height = 73
+      AutoSize = False
+    end
+    object lbl_fileinfo: TLabel
+      Left = 380
+      Top = 0
+      Width = 345
+      Height = 99
+      AutoSize = False
+    end
+    object btn_load: TButton
+      Left = 0
+      Top = 0
+      Width = 81
+      Height = 25
+      Caption = 'Load dat-file'
+      TabOrder = 0
+      OnClick = btn_loadClick
+    end
+    object btn_hexcopy: TButton
+      Left = 295
+      Top = 64
+      Width = 89
+      Height = 33
+      Caption = 'Copy filedata as hex to clipboard'
+      TabOrder = 1
+      WordWrap = True
+      OnClick = btn_hexcopyClick
+    end
+  end
+  object group_progress: TGroupBox
+    Left = 160
+    Top = 384
+    Width = 297
+    Height = 57
+    Caption = 'Extracting...'
+    TabOrder = 2
+    Visible = False
+    object lbl_progress: TLabel
+      Left = 10
+      Top = 36
+      Width = 279
+      Height = 18
+      AutoSize = False
+    end
+    object progress: TProgressBar
+      Left = 8
+      Top = 16
+      Width = 217
+      Height = 17
+      Step = 1
+      TabOrder = 0
+    end
+    object btn_extractcancel: TButton
+      Left = 232
+      Top = 16
+      Width = 57
+      Height = 33
+      Caption = 'Cancel'
+      TabOrder = 1
+      OnClick = btn_extractcancelClick
+    end
+  end
+  object fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    Left = 72
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 128
+    object menu_main: TMenuItem
+      Caption = 'Main'
+      object menu_exit: TMenuItem
+        Caption = 'Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_tools: TMenuItem
+      Caption = 'Tools'
+      object menu_txmpreplace: TMenuItem
+        Caption = 'TXMP replacer'
+        OnClick = menu_txmpreplaceClick
+      end
+    end
+    object menu_preview: TMenuItem
+      Caption = 'Preview Window'
+      OnClick = menu_previewClick
+    end
+  end
+end
Index: /oup/releases/0.12a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.12a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.12a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,383 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace;
+
+TYPE
+  TForm1 = Class(TForm)
+    panel_all: TPanel;
+    panel_left: TPanel;
+    Splitter1: TSplitter;
+    panel_files: TPanel;
+    btn_extractallconvert: TButton;
+    btn_extract: TButton;
+    btn_extractconvert: TButton;
+    list_files: TListBox;
+    btn_extractall: TButton;
+    list_extensions: TListBox;
+    Splitter2: TSplitter;
+    panel_right: TPanel;
+    edit_data: TMemo;
+    list_names: TListBox;
+    Splitter3: TSplitter;
+    panel_info: TPanel;
+    lbl_info: TLabel;
+    btn_load: TButton;
+    btn_hexcopy: TButton;
+    fopen: TOpenDialog;
+    lbl_fileinfo: TLabel;
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    btn_extractcancel: TButton;
+    menu_tools: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    procedure menu_txmpreplaceClick(Sender: TObject);
+    procedure menu_exitClick(Sender: TObject);
+    procedure btn_extractcancelClick(Sender: TObject);
+    PROCEDURE menu_previewClick(Sender: TObject);
+    PROCEDURE btn_extractallconvertClick(Sender: TObject);
+    PROCEDURE Splitter2Moved(Sender: TObject);
+    PROCEDURE Splitter1Moved(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE btn_hexcopyClick(Sender: TObject);
+    PROCEDURE list_extensionsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE btn_extractconvertClick(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE list_filesDblClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form1: TForm1;
+
+IMPLEMENTATION
+{$R *.dfm}
+
+PROCEDURE DoAfterLoadOfADat;
+  VAR
+    i:LongWord;
+    txt:Text;
+    temp4:LongWord;
+    temp2:Word;
+    temp1:Byte;
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='M') AND
+          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXMP' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$88,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$89,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$8C,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$8E,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$90,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='A') AND
+          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXAN' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$14,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$16,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$1C,4,@temp4);
+        Write(txt,IntToHex(temp4,8)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+  END;
+
+PROCEDURE TForm1.btn_loadClick(Sender: TObject);
+  VAR i:LongWord;
+  BEGIN
+    fopen.InitialDir:=AppSettings.DatPath;
+    IF fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(fopen.FileName);
+      list_files.Items.Clear;
+      list_extensions.Items.Clear;
+      list_names.Items.Clear;
+      IF LoadDatInfos(fopen.FileName) THEN BEGIN
+        lbl_info.Caption:=
+              '# of files: '+IntToStr(dat_header.Files)+CrLf+
+              '# of named files: '+IntToStr(dat_header.NamedFiles)+CrLf+
+              '# of extensions: '+IntToStr(dat_header.Extensions)+CrLf+
+              'Address of Body: 0x'+IntToHex(dat_header.DataAddr,8)+CrLf+
+              'Address of End: 0x'+IntToHex(dat_header.NamesAddr,8);
+        list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
+        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+          WITH dat_extensionsmap[i] DO BEGIN
+            list_extensions.Items.Add(
+                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
+                FormatNumber(ExtCount,4,' '));{+' (Ident: 0x'+
+                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');}
+          END;
+        END;
+        FOR i:=0 TO dat_header.namedFiles-1 DO BEGIN
+          WITH dat_namedfilesmap[i] DO BEGIN
+            list_names.Items.Add('0x'+IntToHex(filenumber,8)+': 0x'+IntToHex(blubb,8));
+          END;
+        END;
+        Form1.list_extensions.ItemIndex:=0;
+        Form1.list_extensionsClick(Form1);
+        Form1.list_files.ItemIndex:=0;
+        Form1.list_filesDblClick(Form1);
+
+        Form7.RecreateTXMPlist;
+
+        DoAfterLoadOfADat;
+
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    temp:Tdata;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    lbl_fileinfo.Caption:=
+          'Filename: '+dat_files[id].FileName+CrLf+
+          'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
+          'FileType: 0x'+IntToHex(dat_files[id].FileType,8)+CrLf+
+          'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
+    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
+      temp:=LoadDatFile(id);
+      edit_data.Text:=CreateHexString(temp,False);
+      btn_hexcopy.Visible:=True;
+      IF menu_preview.Checked THEN Form5.ShowPreview(id); 
+    END ELSE BEGIN
+      edit_data.Text:='Zero byte file.'+CrLf+'Oni will take the data for this file of level0_final.dat/raw';
+      btn_hexcopy.Visible:=False;
+    END;
+  END;
+
+PROCEDURE TForm1.FormCreate(Sender: TObject);
+  BEGIN
+    Form1.Caption:='Oni Un/Packer '+version;
+    Form1.FormResize(Form1);
+
+    panel_all.Align:=alClient;
+
+    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;
+
+    //Form1.btn_loadClick(Form1);
+  END;
+
+PROCEDURE TForm1.btn_extractconvertClick(Sender: TObject);
+  VAR
+    result:Integer;
+    id:LongWord;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    IF TComponent(Sender).Name='btn_extract' THEN
+      result:=ExportFile(id,False)
+    ELSE
+      result:=ExportFile(id,True);
+    CASE result OF
+      0{export_noerror}: IF 1=2 THEN BEGIN END;
+      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
+      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
+      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
+    ELSE ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
+    END;
+    Form1.list_files.SetFocus;
+  END;
+
+PROCEDURE TForm1.FormResize(Sender: TObject);
+  CONST
+    MinWidth:Integer=750;
+    MinHeight:Integer=500;
+  BEGIN
+    IF NOT group_progress.Visible THEN BEGIN
+      IF Form1.Width<MinWidth THEN Form1.Width:=MinWidth;
+      IF Form1.Height<MinHeight THEN Form1.Height:=MinHeight;
+    END;
+  END;
+
+PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
+    list_files.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        list_files.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          list_files.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
+  VAR
+    temp:Tdata;
+  BEGIN
+    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
+    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
+  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);
+  END;
+
+PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
+  BEGIN
+    Form1.list_files.Height:=Form1.Splitter1.Top-32;
+    Form1.btn_extractallconvert.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extract.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extractall.Top:=Form1.Splitter1.Top-33;
+  END;
+
+PROCEDURE TForm1.Splitter2Moved(Sender: TObject);
+  BEGIN
+    Form1.btn_extractall.Left:=Form1.Splitter2.Left-146;
+    Form1.btn_extractallconvert.Left:=Form1.Splitter2.Left-83;
+  END;
+
+PROCEDURE TForm1.btn_extractallconvertClick(Sender: TObject);
+  VAR
+    convert:Boolean;
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    panel_info.Visible:=False;
+    group_progress.Visible:=True;
+    menu.Items.Visible:=False;
+    menu.Items.Enabled:=False;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=103;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=dat_header.files;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    IF TComponent(Sender).Name='btn_extractall' THEN
+      convert:=False
+    ELSE
+      convert:=True;
+    errors:=0;
+    FOR i:=0 TO High(dat_files) DO BEGIN
+      IF ExportFile(i,convert)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+    panel_info.Visible:=True;
+    group_progress.Visible:=False;
+  END;
+
+PROCEDURE TForm1.menu_previewClick(Sender: TObject);
+  BEGIN
+    Form5.Visible:=NOT Form5.Visible;
+  END;
+
+PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
+  BEGIN
+    btn_extractcancel.Caption:='Cancel_';
+  END;
+
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+PROCEDURE TForm1.menu_txmpreplaceClick(Sender: TObject);
+  BEGIN
+    Form7.Visible:=NOT Form7.Visible;
+  END;
+
+END.
Index: /oup/releases/0.12a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.12a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.12a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,206 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, Unit3_data, Unit4_Exporters;
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    IF Length(filename)>0 THEN dat_file.Free;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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>=1024*1024*1024 THEN BEGIN
+      Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB';
+    END ELSE BEGIN
+      IF size>=1024*1024 THEN BEGIN
+        Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB';
+      END ELSE BEGIN
+        IF size>=1024 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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.12a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.12a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.12a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,84 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.12a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  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;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.12a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.12a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.12a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,180 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DAT_'),fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.12a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.12a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.12a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,74 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 435
+  Height = 348
+  BorderStyle = bsSizeToolWin
+  Caption = 'Preview'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object img: TImage
+    Left = 0
+    Top = 20
+    Width = 427
+    Height = 304
+    Align = alClient
+  end
+  object panel_buttons: TPanel
+    Left = 0
+    Top = 0
+    Width = 427
+    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
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 72
+    Top = 48
+  end
+end
Index: /oup/releases/0.12a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.12a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.12a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,189 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    img: TImage;
+    timer: TTimer;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    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 FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE ShowPreview(fileid:LongWord);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  memstreams:Array OF TMemoryStream;
+  actualimg:Byte;
+  _fileid:LongWord;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE PreviewTXMP;
+  VAR
+    data:Tdata;
+    img:TImgPackage;
+  BEGIN
+    {
+    tempdata:=ResizeImage(imgx,imgy,imgdepth,tempdata);
+    imgx:=imgx DIV 2;
+    imgy:=imgy DIV 2;
+    datasize:=datasize DIV 4;
+    }
+    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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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;
+    Form5.timer.Interval:=Floor(loop_speed*(1/60)*1000);
+    Form5.timer.Enabled:=False;
+    Form5.btn_startstopClick(Form5); 
+    Form5.panel_buttons.Visible:=True;
+  END;
+
+PROCEDURE TForm5.ShowPreview(fileid:LongWord);
+  BEGIN
+    _fileid:=fileid;
+    Form5.timer.Enabled:=False;
+    Form5.panel_buttons.Visible:=False;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[fileid].Extension='TXAN' THEN PreviewTXAN;
+    IF dat_files[fileid].Extension='TXMB' THEN PreviewTXMB;
+    IF dat_files[fileid].Extension='TXMP' THEN PreviewTXMP;
+  END;
+
+PROCEDURE TForm5.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form5.Visible:=False;
+  END;
+
+PROCEDURE TForm5.FormCreate(Sender: TObject);
+  BEGIN
+    SetLength(memstreams,1);
+    memstreams[0]:=TMemoryStream.Create;
+    Form5.Width:=170;
+    Form5.Height:=200;
+  END;
+
+PROCEDURE TForm5.timerTimer(Sender: TObject);
+  BEGIN
+    Inc(actualimg);
+    IF actualimg>=Length(memstreams) THEN actualimg:=0;
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+    Form5.Caption:='Preview '+dat_files[_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
+    Form5.timer.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_dec.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_inc.Enabled:=NOT Form5.timer.Enabled;
+    IF Form5.timer.Enabled THEN
+      Form5.btn_startstop.Caption:='Stop automatic'
+    ELSE
+      Form5.btn_startstop.Caption:='Start automatic';
+  END;
+
+PROCEDURE TForm5.FormResize(Sender: TObject);
+  BEGIN
+    IF Form5.Width>=150 THEN BEGIN
+    END ELSE Form5.Width:=150;
+    IF Form5.Height>=150 THEN BEGIN
+    END ELSE Form5.Height:=150;
+  END;
+
+PROCEDURE TForm5.btn_decClick(Sender: TObject);
+  BEGIN
+    IF actualimg>0 THEN
+      Dec(actualimg)
+    ELSE
+      actualimg:=High(memstreams);
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.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;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+END.
Index: /oup/releases/0.12a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.12a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.12a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,326 @@
+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):TImgPackage;
+FUNCTION LoadTXMBconnected(fileid:LongWord):TImgPackage;
+FUNCTION LoadImgData(fileid:LongWord):TImgPackage;
+
+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,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]:=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;
+      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):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;
+    Result.imgdepth:=16;
+    Result.storetype:=1;
+
+    SetLength(Result.imgdata,Result.imgx*Result.imgy*2);
+    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;
+
+    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));
+    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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,Result.datasize,@Result.imgdata[0]);
+  END;
+
+END.
Index: /oup/releases/0.12a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.12a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.12a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,134 @@
+object Form7: TForm7
+  Left = 0
+  Top = 0
+  Width = 400
+  Height = 350
+  BorderStyle = bsSizeToolWin
+  Caption = 'TXMP Replacer'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_12: TPanel
+    Left = 0
+    Top = 0
+    Width = 392
+    Height = 298
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter1: TSplitter
+      Left = 200
+      Top = 0
+      Width = 8
+      Height = 298
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object group_txmpselect: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 200
+      Height = 298
+      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 = 98
+        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
+    end
+    object group_bmpselect: TGroupBox
+      Left = 208
+      Top = 0
+      Width = 184
+      Height = 298
+      Align = alClient
+      Caption = '2. Open BMP to replace with'
+      Enabled = False
+      TabOrder = 1
+      object image_bmppreview: TImage
+        Left = 2
+        Top = 45
+        Width = 180
+        Height = 251
+        Align = alClient
+      end
+      object panel_load: TPanel
+        Left = 2
+        Top = 15
+        Width = 180
+        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 panel_main: TPanel
+    Left = 0
+    Top = 298
+    Width = 392
+    Height = 28
+    Align = alBottom
+    BevelOuter = bvNone
+    Enabled = False
+    TabOrder = 1
+    object btn_replace: TButton
+      Left = 2
+      Top = 2
+      Width = 185
+      Height = 25
+      Caption = 'Replace'
+      TabOrder = 0
+      OnClick = btn_replaceClick
+    end
+  end
+  object opend: TOpenDialog
+    Filter = '24bit Bitmap (*.bmp)|*.bmp'
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 352
+    Top = 16
+  end
+end
Index: /oup/releases/0.12a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.12a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.12a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,162 @@
+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;
+    image_txmppreview: TImage;
+    list_txmp: TListBox;
+    Splitter1: TSplitter;
+    group_bmpselect: TGroupBox;
+    panel_main: TPanel;
+    btn_replace: TButton;
+    panel_load: TPanel;
+    btn_load: TButton;
+    image_bmppreview: TImage;
+    opend: TOpenDialog;
+    PROCEDURE btn_replaceClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+    PROCEDURE list_txmpClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE RecreateTXMPlist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit6_imgfuncs;
+{$R *.dfm}
+VAR
+  actual_bmpdata:Tdata;
+
+PROCEDURE TForm7.RecreateTXMPlist;
+  VAR
+    i:LongWord;
+  BEGIN
+    Form7.list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        Form7.list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    Form7.group_bmpselect.Enabled:=False;
+  END;
+
+PROCEDURE TForm7.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form7.Visible:=False;
+  END;
+
+PROCEDURE TForm7.FormResize(Sender: TObject);
+  BEGIN
+    IF Form7.Width>=400 THEN BEGIN
+    END ELSE Form7.Width:=400;
+    IF Form7.Height>=350 THEN BEGIN
+    END ELSE Form7.Height:=350;
+  END;
+
+PROCEDURE TForm7.list_txmpClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    data:Tdata;
+    img:TImgPackage;
+    mem:TMemoryStream;
+  BEGIN
+    id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+
+    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);
+    Form7.image_txmppreview.Picture.Bitmap.LoadFromStream(mem);
+    mem.Free;
+
+    Form7.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);
+      Form7.image_bmppreview.Picture.Bitmap.LoadFromStream(mem);
+      mem.Free;
+
+      Form7.panel_main.Enabled:=True;
+    END;
+  END;
+
+PROCEDURE TForm7.btn_replaceClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    imgpkg:TImgPackage;
+    rawfile:TFileStream;
+    datfile:TFileStream;
+    dataddr:LongWord;
+    new_rawaddr:LongWord;
+    oldwidth,oldheight:Word;
+    datword:Word;
+  BEGIN
+    IF Form7.list_txmp.ItemIndex>=0 THEN BEGIN
+      imgpkg:=BmpToImgdata(actual_bmpdata);
+      rawfile:=TFileStream.Create(raw_filename,fmOpenReadWrite);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      IF (oldwidth<>imgpkg.imgx) OR (oldheight<>imgpkg.imgy) THEN BEGIN
+        IF MessageBox(Form7.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('Really replace?'),
+                    MB_YESNO)=IDNO THEN Exit;
+      END;
+      new_rawaddr:=rawfile.Size;
+
+      datword:=$1000;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datword,2);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      datword:=$0001;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datword,2);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      rawfile.Seek(new_rawaddr,soFromBeginning);
+      rawfile.Write(imgpkg.imgdata[0],Length(imgpkg.imgdata)); 
+      rawfile.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.13a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.13a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.13a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.13a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.13a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.13a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,13 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.13a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.13a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.13a/src/OniUnPacker.cfg	(revision 8)
@@ -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.13a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.13a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.13a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,21 @@
+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};
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm5, Form5);
+  Application.CreateForm(TForm7, Form7);
+  Application.Run;
+END.
Index: /oup/releases/0.13a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.13a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.13a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,301 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 435
+  ClientWidth = 742
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = menu
+  OldCreateOrder = False
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_all: TPanel
+    Left = 0
+    Top = 100
+    Width = 692
+    Height = 300
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter2: TSplitter
+      Left = 360
+      Top = 0
+      Width = 8
+      Height = 300
+      AutoSnap = False
+      Beveled = True
+      MinSize = 360
+      OnMoved = Splitter2Moved
+    end
+    object panel_left: TPanel
+      Left = 0
+      Top = 0
+      Width = 360
+      Height = 300
+      Cursor = crDrag
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object Splitter1: TSplitter
+        Left = 0
+        Top = 241
+        Width = 360
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+        OnMoved = Splitter1Moved
+      end
+      object panel_files: TPanel
+        Left = 0
+        Top = 0
+        Width = 360
+        Height = 241
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_extractallconvert: TButton
+          Left = 273
+          Top = 208
+          Width = 82
+          Height = 33
+          Caption = 'Extract all (with convert)'
+          TabOrder = 0
+          WordWrap = True
+          OnClick = btn_extractallconvertClick
+        end
+        object btn_extract: TButton
+          Left = 0
+          Top = 208
+          Width = 100
+          Height = 33
+          Caption = 'Extract file (without convert)'
+          TabOrder = 1
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object btn_extractconvert: TButton
+          Left = 101
+          Top = 208
+          Width = 105
+          Height = 33
+          Caption = 'Extract file (with convert if possible)'
+          TabOrder = 2
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object list_files: TListBox
+          Left = 0
+          Top = 0
+          Width = 360
+          Height = 209
+          Align = alTop
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Fixedsys'
+          Font.Style = []
+          ItemHeight = 15
+          ParentFont = False
+          TabOrder = 3
+          OnClick = list_filesDblClick
+          OnDblClick = list_filesDblClick
+        end
+        object btn_extractall: TButton
+          Left = 210
+          Top = 208
+          Width = 62
+          Height = 33
+          Caption = 'Extract all'
+          TabOrder = 4
+          WordWrap = True
+          OnClick = btn_extractallconvertClick
+        end
+      end
+      object list_extensions: TListBox
+        Left = 0
+        Top = 249
+        Width = 360
+        Height = 51
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+        OnClick = list_extensionsClick
+        OnDblClick = list_extensionsClick
+      end
+    end
+    object panel_right: TPanel
+      Left = 368
+      Top = 0
+      Width = 324
+      Height = 300
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 1
+      object Splitter3: TSplitter
+        Left = 0
+        Top = 200
+        Width = 324
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+      end
+      object edit_data: TMemo
+        Left = 0
+        Top = 0
+        Width = 324
+        Height = 200
+        Align = alTop
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -13
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ParentFont = False
+        ReadOnly = True
+        ScrollBars = ssVertical
+        TabOrder = 0
+        WordWrap = False
+      end
+      object list_names: TListBox
+        Left = 0
+        Top = 208
+        Width = 324
+        Height = 92
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+      end
+    end
+  end
+  object panel_info: TPanel
+    Left = 0
+    Top = 0
+    Width = 742
+    Height = 100
+    Align = alTop
+    BevelOuter = bvNone
+    TabOrder = 1
+    object lbl_info: TLabel
+      Left = 2
+      Top = 26
+      Width = 345
+      Height = 73
+      AutoSize = False
+    end
+    object lbl_fileinfo: TLabel
+      Left = 380
+      Top = 0
+      Width = 345
+      Height = 99
+      AutoSize = False
+    end
+    object btn_load: TButton
+      Left = 0
+      Top = 0
+      Width = 81
+      Height = 25
+      Caption = 'Load dat-file'
+      TabOrder = 0
+      OnClick = btn_loadClick
+    end
+    object btn_hexcopy: TButton
+      Left = 295
+      Top = 64
+      Width = 89
+      Height = 33
+      Caption = 'Copy filedata as hex to clipboard'
+      TabOrder = 1
+      WordWrap = True
+      OnClick = btn_hexcopyClick
+    end
+  end
+  object group_progress: TGroupBox
+    Left = 160
+    Top = 384
+    Width = 297
+    Height = 57
+    Caption = 'Extracting...'
+    TabOrder = 2
+    Visible = False
+    object lbl_progress: TLabel
+      Left = 10
+      Top = 36
+      Width = 279
+      Height = 18
+      AutoSize = False
+    end
+    object progress: TProgressBar
+      Left = 8
+      Top = 16
+      Width = 217
+      Height = 17
+      Step = 1
+      TabOrder = 0
+    end
+    object btn_extractcancel: TButton
+      Left = 232
+      Top = 16
+      Width = 57
+      Height = 33
+      Caption = 'Cancel'
+      TabOrder = 1
+      OnClick = btn_extractcancelClick
+    end
+  end
+  object fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    Left = 72
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 128
+    object menu_main: TMenuItem
+      Caption = 'Main'
+      object menu_exit: TMenuItem
+        Caption = 'Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_tools: TMenuItem
+      Caption = 'Tools'
+      object menu_txmpreplace: TMenuItem
+        Caption = 'TXMP replacer'
+        OnClick = menu_txmpreplaceClick
+      end
+    end
+    object menu_preview: TMenuItem
+      Caption = 'Preview Window'
+      OnClick = menu_previewClick
+    end
+  end
+end
Index: /oup/releases/0.13a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.13a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.13a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,383 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace;
+
+TYPE
+  TForm1 = Class(TForm)
+    panel_all: TPanel;
+    panel_left: TPanel;
+    Splitter1: TSplitter;
+    panel_files: TPanel;
+    btn_extractallconvert: TButton;
+    btn_extract: TButton;
+    btn_extractconvert: TButton;
+    list_files: TListBox;
+    btn_extractall: TButton;
+    list_extensions: TListBox;
+    Splitter2: TSplitter;
+    panel_right: TPanel;
+    edit_data: TMemo;
+    list_names: TListBox;
+    Splitter3: TSplitter;
+    panel_info: TPanel;
+    lbl_info: TLabel;
+    btn_load: TButton;
+    btn_hexcopy: TButton;
+    fopen: TOpenDialog;
+    lbl_fileinfo: TLabel;
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    btn_extractcancel: TButton;
+    menu_tools: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    PROCEDURE menu_txmpreplaceClick(Sender: TObject);
+    PROCEDURE menu_exitClick(Sender: TObject);
+    PROCEDURE btn_extractcancelClick(Sender: TObject);
+    PROCEDURE menu_previewClick(Sender: TObject);
+    PROCEDURE btn_extractallconvertClick(Sender: TObject);
+    PROCEDURE Splitter2Moved(Sender: TObject);
+    PROCEDURE Splitter1Moved(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE btn_hexcopyClick(Sender: TObject);
+    PROCEDURE list_extensionsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE btn_extractconvertClick(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE list_filesDblClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form1: TForm1;
+
+IMPLEMENTATION
+{$R *.dfm}
+
+PROCEDURE DoAfterLoadOfADat;
+  VAR
+    i:LongWord;
+    txt:Text;
+    temp4:LongWord;
+    temp2:Word;
+    temp1:Byte;
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='M') AND
+          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXMP' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$88,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$89,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$8C,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$8E,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$90,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='A') AND
+          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXAN' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$14,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$16,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$1C,4,@temp4);
+        Write(txt,IntToHex(temp4,8)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+  END;
+
+PROCEDURE TForm1.btn_loadClick(Sender: TObject);
+  VAR i:LongWord;
+  BEGIN
+    fopen.InitialDir:=AppSettings.DatPath;
+    IF fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(fopen.FileName);
+      list_files.Items.Clear;
+      list_extensions.Items.Clear;
+      list_names.Items.Clear;
+      IF LoadDatInfos(fopen.FileName) THEN BEGIN
+        lbl_info.Caption:=
+              '# of files: '+IntToStr(dat_header.Files)+CrLf+
+              '# of named files: '+IntToStr(dat_header.NamedFiles)+CrLf+
+              '# of extensions: '+IntToStr(dat_header.Extensions)+CrLf+
+              'Address of Body: 0x'+IntToHex(dat_header.DataAddr,8)+CrLf+
+              'Address of End: 0x'+IntToHex(dat_header.NamesAddr,8);
+        list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
+        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+          WITH dat_extensionsmap[i] DO BEGIN
+            list_extensions.Items.Add(
+                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
+                FormatNumber(ExtCount,4,' '));{+' (Ident: 0x'+
+                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');}
+          END;
+        END;
+        FOR i:=0 TO dat_header.namedFiles-1 DO BEGIN
+          WITH dat_namedfilesmap[i] DO BEGIN
+            list_names.Items.Add('0x'+IntToHex(filenumber,8)+': 0x'+IntToHex(blubb,8));
+          END;
+        END;
+        Form1.list_extensions.ItemIndex:=0;
+        Form1.list_extensionsClick(Form1);
+        Form1.list_files.ItemIndex:=0;
+        Form1.list_filesDblClick(Form1);
+
+        Form7.RecreateTXMPlist;
+
+        DoAfterLoadOfADat;
+
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    temp:Tdata;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    lbl_fileinfo.Caption:=
+          'Filename: '+dat_files[id].FileName+CrLf+
+          'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
+          'FileType: 0x'+IntToHex(dat_files[id].FileType,8)+CrLf+
+          'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
+    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
+      temp:=LoadDatFile(id);
+      edit_data.Text:=CreateHexString(temp,False);
+      btn_hexcopy.Visible:=True;
+      IF Form5.Visible THEN Form5.ShowPreview(id); 
+    END ELSE BEGIN
+      edit_data.Text:='Zero byte file.'+CrLf+'Oni will take the data for this file of level0_final.dat/raw';
+      btn_hexcopy.Visible:=False;
+    END;
+  END;
+
+PROCEDURE TForm1.FormCreate(Sender: TObject);
+  BEGIN
+    Form1.Caption:='Oni Un/Packer '+version;
+    Form1.FormResize(Form1);
+
+    panel_all.Align:=alClient;
+
+    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;
+
+    //Form1.btn_loadClick(Form1);
+  END;
+
+PROCEDURE TForm1.btn_extractconvertClick(Sender: TObject);
+  VAR
+    result:Integer;
+    id:LongWord;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    IF TComponent(Sender).Name='btn_extract' THEN
+      result:=ExportFile(id,False)
+    ELSE
+      result:=ExportFile(id,True);
+    CASE result OF
+      0{export_noerror}: IF 1=2 THEN BEGIN END;
+      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
+      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
+      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
+    ELSE ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
+    END;
+    Form1.list_files.SetFocus;
+  END;
+
+PROCEDURE TForm1.FormResize(Sender: TObject);
+  CONST
+    MinWidth:Integer=750;
+    MinHeight:Integer=500;
+  BEGIN
+    IF NOT group_progress.Visible THEN BEGIN
+      IF Form1.Width<MinWidth THEN Form1.Width:=MinWidth;
+      IF Form1.Height<MinHeight THEN Form1.Height:=MinHeight;
+    END;
+  END;
+
+PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
+    list_files.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        list_files.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          list_files.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
+  VAR
+    temp:Tdata;
+  BEGIN
+    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
+    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
+  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);
+  END;
+
+PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
+  BEGIN
+    Form1.list_files.Height:=Form1.Splitter1.Top-32;
+    Form1.btn_extractallconvert.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extract.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extractall.Top:=Form1.Splitter1.Top-33;
+  END;
+
+PROCEDURE TForm1.Splitter2Moved(Sender: TObject);
+  BEGIN
+    Form1.btn_extractall.Left:=Form1.Splitter2.Left-146;
+    Form1.btn_extractallconvert.Left:=Form1.Splitter2.Left-83;
+  END;
+
+PROCEDURE TForm1.btn_extractallconvertClick(Sender: TObject);
+  VAR
+    convert:Boolean;
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    panel_info.Visible:=False;
+    group_progress.Visible:=True;
+    menu.Items.Visible:=False;
+    menu.Items.Enabled:=False;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=103;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=dat_header.files;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    IF TComponent(Sender).Name='btn_extractall' THEN
+      convert:=False
+    ELSE
+      convert:=True;
+    errors:=0;
+    FOR i:=0 TO High(dat_files) DO BEGIN
+      IF ExportFile(i,convert)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+    panel_info.Visible:=True;
+    group_progress.Visible:=False;
+  END;
+
+PROCEDURE TForm1.menu_previewClick(Sender: TObject);
+  BEGIN
+    Form5.Visible:=NOT Form5.Visible;
+  END;
+
+PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
+  BEGIN
+    btn_extractcancel.Caption:='Cancel_';
+  END;
+
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+PROCEDURE TForm1.menu_txmpreplaceClick(Sender: TObject);
+  BEGIN
+    Form7.Visible:=NOT Form7.Visible;
+  END;
+
+END.
Index: /oup/releases/0.13a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.13a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.13a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,206 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, Unit3_data, Unit4_Exporters;
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    IF Length(filename)>0 THEN dat_file.Free;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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>=1024*1024*1024 THEN BEGIN
+      Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB';
+    END ELSE BEGIN
+      IF size>=1024*1024 THEN BEGIN
+        Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB';
+      END ELSE BEGIN
+        IF size>=1024 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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.13a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.13a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.13a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,84 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.13a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  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;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.13a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.13a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.13a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,180 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DAT_'),fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.13a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.13a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.13a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,74 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 435
+  Height = 348
+  BorderStyle = bsSizeToolWin
+  Caption = 'Preview'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object img: TImage
+    Left = 0
+    Top = 20
+    Width = 427
+    Height = 304
+    Align = alClient
+  end
+  object panel_buttons: TPanel
+    Left = 0
+    Top = 0
+    Width = 427
+    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
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 72
+    Top = 48
+  end
+end
Index: /oup/releases/0.13a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.13a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.13a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,189 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    img: TImage;
+    timer: TTimer;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    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 FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE ShowPreview(fileid:LongWord);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  memstreams:Array OF TMemoryStream;
+  actualimg:Byte;
+  _fileid:LongWord;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE PreviewTXMP;
+  VAR
+    data:Tdata;
+    img:TImgPackage;
+  BEGIN
+    {
+    tempdata:=ResizeImage(imgx,imgy,imgdepth,tempdata);
+    imgx:=imgx DIV 2;
+    imgy:=imgy DIV 2;
+    datasize:=datasize DIV 4;
+    }
+    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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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;
+    Form5.timer.Interval:=Floor(loop_speed*(1/60)*1000);
+    Form5.timer.Enabled:=False;
+    Form5.btn_startstopClick(Form5); 
+    Form5.panel_buttons.Visible:=True;
+  END;
+
+PROCEDURE TForm5.ShowPreview(fileid:LongWord);
+  BEGIN
+    _fileid:=fileid;
+    Form5.timer.Enabled:=False;
+    Form5.panel_buttons.Visible:=False;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[fileid].Extension='TXAN' THEN PreviewTXAN;
+    IF dat_files[fileid].Extension='TXMB' THEN PreviewTXMB;
+    IF dat_files[fileid].Extension='TXMP' THEN PreviewTXMP;
+  END;
+
+PROCEDURE TForm5.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form5.Visible:=False;
+  END;
+
+PROCEDURE TForm5.FormCreate(Sender: TObject);
+  BEGIN
+    SetLength(memstreams,1);
+    memstreams[0]:=TMemoryStream.Create;
+    Form5.Width:=170;
+    Form5.Height:=200;
+  END;
+
+PROCEDURE TForm5.timerTimer(Sender: TObject);
+  BEGIN
+    Inc(actualimg);
+    IF actualimg>=Length(memstreams) THEN actualimg:=0;
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+    Form5.Caption:='Preview '+dat_files[_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
+    Form5.timer.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_dec.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_inc.Enabled:=NOT Form5.timer.Enabled;
+    IF Form5.timer.Enabled THEN
+      Form5.btn_startstop.Caption:='Stop automatic'
+    ELSE
+      Form5.btn_startstop.Caption:='Start automatic';
+  END;
+
+PROCEDURE TForm5.FormResize(Sender: TObject);
+  BEGIN
+    IF Form5.Width>=150 THEN BEGIN
+    END ELSE Form5.Width:=150;
+    IF Form5.Height>=150 THEN BEGIN
+    END ELSE Form5.Height:=150;
+  END;
+
+PROCEDURE TForm5.btn_decClick(Sender: TObject);
+  BEGIN
+    IF actualimg>0 THEN
+      Dec(actualimg)
+    ELSE
+      actualimg:=High(memstreams);
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.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;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+END.
Index: /oup/releases/0.13a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.13a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.13a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,372 @@
+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):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,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]:=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;
+      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):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;
+    Result.imgdepth:=16;
+    Result.storetype:=1;
+
+    SetLength(Result.imgdata,Result.imgx*Result.imgy*2);
+    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;
+
+    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));
+    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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,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*2);
+    SetLength(fadelvldata,x*y*2);
+    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,16,fadelvldata);
+      x:=x DIV 2;
+      y:=y DIV 2;
+      SetLength(imgdata,Length(imgdata)+x*y*2);
+      FOR i:=0 TO Length(fadelvldata)-1 DO imgdata[Length(imgdata)-x*y*2+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.13a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.13a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.13a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,150 @@
+object Form7: TForm7
+  Left = 0
+  Top = 0
+  Width = 400
+  Height = 453
+  BorderStyle = bsSizeToolWin
+  Caption = 'TXMP Replacer'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_12: TPanel
+    Left = 0
+    Top = 0
+    Width = 392
+    Height = 350
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter1: TSplitter
+      Left = 200
+      Top = 0
+      Width = 8
+      Height = 350
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object group_txmpselect: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 200
+      Height = 350
+      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 = 150
+        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
+    end
+    object group_bmpselect: TGroupBox
+      Left = 208
+      Top = 0
+      Width = 184
+      Height = 350
+      Align = alClient
+      Caption = '2. Open BMP to replace with'
+      Enabled = False
+      TabOrder = 1
+      object image_bmppreview: TImage
+        Left = 2
+        Top = 45
+        Width = 180
+        Height = 303
+        Align = alClient
+      end
+      object panel_load: TPanel
+        Left = 2
+        Top = 15
+        Width = 180
+        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 = 350
+    Width = 392
+    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
+  end
+  object opend: TOpenDialog
+    Filter = '24bit Bitmap (*.bmp)|*.bmp'
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 352
+    Top = 16
+  end
+end
Index: /oup/releases/0.13a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.13a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.13a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,210 @@
+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;
+    image_txmppreview: TImage;
+    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;
+    PROCEDURE btn_replaceClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+    PROCEDURE list_txmpClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE RecreateTXMPlist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit6_imgfuncs;
+{$R *.dfm}
+VAR
+  actual_bmpdata:Tdata;
+
+PROCEDURE TForm7.RecreateTXMPlist;
+  VAR
+    i:LongWord;
+  BEGIN
+    Form7.list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        Form7.list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    Form7.group_bmpselect.Enabled:=False;
+    //Form7.image_txmppreview.Picture.Free;
+    //Form7.image_txmppreview.Picture.Create;
+    Form7.check_transparency.Checked:=False;
+    Form7.check_fading.Checked:=False;
+  END;
+
+PROCEDURE TForm7.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form7.Visible:=False;
+  END;
+
+PROCEDURE TForm7.FormResize(Sender: TObject);
+  BEGIN
+    IF Form7.Width>=400 THEN BEGIN
+    END ELSE Form7.Width:=400;
+    IF Form7.Height>=350 THEN BEGIN
+    END ELSE Form7.Height:=350;
+  END;
+
+PROCEDURE TForm7.list_txmpClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    data:Tdata;
+    img:TImgPackage;
+    mem:TMemoryStream;
+    fadingbyte,depthbyte: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);
+    Form7.check_fading.Checked:=(fadingbyte AND $01)>0;
+    Form7.check_transparency.Checked:=(depthbyte AND $04)>0;
+
+    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);
+    Form7.image_txmppreview.Picture.Bitmap.LoadFromStream(mem);
+    mem.Free;
+
+    Form7.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);
+      Form7.image_bmppreview.Picture.Bitmap.LoadFromStream(mem);
+      mem.Free;
+
+      Form7.group_options.Enabled:=True;
+    END;
+  END;
+
+PROCEDURE TForm7.btn_replaceClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    imgpkg:TImgPackage;
+    rawfile:TFileStream;
+    datfile:TFileStream;
+    dataddr:LongWord;
+    old_rawaddr,new_rawaddr:LongWord;
+    oldwidth,oldheight:Word;
+    oldstore,olddepth,oldfading:Byte;
+    oldsize:LongWord;
+    newsize:LongWord;
+    datword,datbyte:Word;
+  BEGIN
+    IF Form7.list_txmp.ItemIndex>=0 THEN BEGIN
+      imgpkg:=BmpToImgdata(actual_bmpdata);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Read(oldfading,1);
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Read(olddepth,1);
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Read(oldstore,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Read(old_rawaddr,4);
+      IF (oldwidth<>imgpkg.imgx) OR (oldheight<>imgpkg.imgy) THEN BEGIN
+        IF MessageBox(Form7.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('Really replace?'),
+                    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;
+      newsize:=GetImageDataSize(imgpkg.imgx,imgpkg.imgy,16,Form7.check_fading.Checked);
+
+      IF newsize<=oldsize THEN
+        new_rawaddr:=old_rawaddr
+      ELSE
+        new_rawaddr:=rawfile.Size;
+
+      datbyte:=$00;
+      IF Form7.check_fading.Checked THEN datbyte:=datbyte OR $01;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datbyte,2);
+      datbyte:=$10;
+      IF Form7.check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Write(datbyte,2);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      datword:=$0001;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datword,2);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      IF Form7.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;
+
+END.
Index: /oup/releases/0.14a/_changelog.txt
===================================================================
--- /oup/releases/0.14a/_changelog.txt	(revision 8)
+++ /oup/releases/0.14a/_changelog.txt	(revision 8)
@@ -0,0 +1,15 @@
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.14a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.14a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.14a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.14a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.14a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.14a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,13 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.14a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.14a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.14a/src/OniUnPacker.cfg	(revision 8)
@@ -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.14a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.14a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.14a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,21 @@
+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};
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm5, Form5);
+  Application.CreateForm(TForm7, Form7);
+  Application.Run;
+END.
Index: /oup/releases/0.14a/src/SQLite3.pas
===================================================================
--- /oup/releases/0.14a/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.14a/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.14a/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.14a/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.14a/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,883 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.14a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.14a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.14a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,301 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 435
+  ClientWidth = 742
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = menu
+  OldCreateOrder = False
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_all: TPanel
+    Left = 0
+    Top = 100
+    Width = 692
+    Height = 300
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter2: TSplitter
+      Left = 360
+      Top = 0
+      Width = 8
+      Height = 300
+      AutoSnap = False
+      Beveled = True
+      MinSize = 360
+      OnMoved = Splitter2Moved
+    end
+    object panel_left: TPanel
+      Left = 0
+      Top = 0
+      Width = 360
+      Height = 300
+      Cursor = crDrag
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object Splitter1: TSplitter
+        Left = 0
+        Top = 241
+        Width = 360
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+        OnMoved = Splitter1Moved
+      end
+      object panel_files: TPanel
+        Left = 0
+        Top = 0
+        Width = 360
+        Height = 241
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_extractallconvert: TButton
+          Left = 273
+          Top = 208
+          Width = 82
+          Height = 33
+          Caption = 'Extract all (with convert)'
+          TabOrder = 0
+          WordWrap = True
+          OnClick = btn_extractallconvertClick
+        end
+        object btn_extract: TButton
+          Left = 0
+          Top = 208
+          Width = 100
+          Height = 33
+          Caption = 'Extract file (without convert)'
+          TabOrder = 1
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object btn_extractconvert: TButton
+          Left = 101
+          Top = 208
+          Width = 105
+          Height = 33
+          Caption = 'Extract file (with convert if possible)'
+          TabOrder = 2
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object list_files: TListBox
+          Left = 0
+          Top = 0
+          Width = 360
+          Height = 209
+          Align = alTop
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Fixedsys'
+          Font.Style = []
+          ItemHeight = 15
+          ParentFont = False
+          TabOrder = 3
+          OnClick = list_filesDblClick
+          OnDblClick = list_filesDblClick
+        end
+        object btn_extractall: TButton
+          Left = 210
+          Top = 208
+          Width = 62
+          Height = 33
+          Caption = 'Extract all'
+          TabOrder = 4
+          WordWrap = True
+          OnClick = btn_extractallconvertClick
+        end
+      end
+      object list_extensions: TListBox
+        Left = 0
+        Top = 249
+        Width = 360
+        Height = 51
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+        OnClick = list_extensionsClick
+        OnDblClick = list_extensionsClick
+      end
+    end
+    object panel_right: TPanel
+      Left = 368
+      Top = 0
+      Width = 324
+      Height = 300
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 1
+      object Splitter3: TSplitter
+        Left = 0
+        Top = 200
+        Width = 324
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+      end
+      object edit_data: TMemo
+        Left = 0
+        Top = 0
+        Width = 324
+        Height = 200
+        Align = alTop
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -13
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ParentFont = False
+        ReadOnly = True
+        ScrollBars = ssVertical
+        TabOrder = 0
+        WordWrap = False
+      end
+      object list_names: TListBox
+        Left = 0
+        Top = 208
+        Width = 324
+        Height = 92
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+      end
+    end
+  end
+  object panel_info: TPanel
+    Left = 0
+    Top = 0
+    Width = 742
+    Height = 100
+    Align = alTop
+    BevelOuter = bvNone
+    TabOrder = 1
+    object lbl_info: TLabel
+      Left = 2
+      Top = 26
+      Width = 345
+      Height = 73
+      AutoSize = False
+    end
+    object lbl_fileinfo: TLabel
+      Left = 380
+      Top = 0
+      Width = 345
+      Height = 99
+      AutoSize = False
+    end
+    object btn_load: TButton
+      Left = 0
+      Top = 0
+      Width = 81
+      Height = 25
+      Caption = 'Load dat-file'
+      TabOrder = 0
+      OnClick = btn_loadClick
+    end
+    object btn_hexcopy: TButton
+      Left = 295
+      Top = 64
+      Width = 89
+      Height = 33
+      Caption = 'Copy filedata as hex to clipboard'
+      TabOrder = 1
+      WordWrap = True
+      OnClick = btn_hexcopyClick
+    end
+  end
+  object group_progress: TGroupBox
+    Left = 160
+    Top = 384
+    Width = 297
+    Height = 57
+    Caption = 'Extracting...'
+    TabOrder = 2
+    Visible = False
+    object lbl_progress: TLabel
+      Left = 10
+      Top = 36
+      Width = 279
+      Height = 18
+      AutoSize = False
+    end
+    object progress: TProgressBar
+      Left = 8
+      Top = 16
+      Width = 217
+      Height = 17
+      Step = 1
+      TabOrder = 0
+    end
+    object btn_extractcancel: TButton
+      Left = 232
+      Top = 16
+      Width = 57
+      Height = 33
+      Caption = 'Cancel'
+      TabOrder = 1
+      OnClick = btn_extractcancelClick
+    end
+  end
+  object fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    Left = 72
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 128
+    object menu_main: TMenuItem
+      Caption = 'Main'
+      object menu_exit: TMenuItem
+        Caption = 'Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_tools: TMenuItem
+      Caption = 'Tools'
+      object menu_txmpreplace: TMenuItem
+        Caption = 'TXMP replacer'
+        OnClick = menu_txmpreplaceClick
+      end
+    end
+    object menu_preview: TMenuItem
+      Caption = 'Preview Window'
+      OnClick = menu_previewClick
+    end
+  end
+end
Index: /oup/releases/0.14a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.14a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.14a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,383 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace;
+
+TYPE
+  TForm1 = Class(TForm)
+    panel_all: TPanel;
+    panel_left: TPanel;
+    Splitter1: TSplitter;
+    panel_files: TPanel;
+    btn_extractallconvert: TButton;
+    btn_extract: TButton;
+    btn_extractconvert: TButton;
+    list_files: TListBox;
+    btn_extractall: TButton;
+    list_extensions: TListBox;
+    Splitter2: TSplitter;
+    panel_right: TPanel;
+    edit_data: TMemo;
+    list_names: TListBox;
+    Splitter3: TSplitter;
+    panel_info: TPanel;
+    lbl_info: TLabel;
+    btn_load: TButton;
+    btn_hexcopy: TButton;
+    fopen: TOpenDialog;
+    lbl_fileinfo: TLabel;
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    btn_extractcancel: TButton;
+    menu_tools: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    PROCEDURE menu_txmpreplaceClick(Sender: TObject);
+    PROCEDURE menu_exitClick(Sender: TObject);
+    PROCEDURE btn_extractcancelClick(Sender: TObject);
+    PROCEDURE menu_previewClick(Sender: TObject);
+    PROCEDURE btn_extractallconvertClick(Sender: TObject);
+    PROCEDURE Splitter2Moved(Sender: TObject);
+    PROCEDURE Splitter1Moved(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE btn_hexcopyClick(Sender: TObject);
+    PROCEDURE list_extensionsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE btn_extractconvertClick(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE list_filesDblClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form1: TForm1;
+
+IMPLEMENTATION
+{$R *.dfm}
+
+PROCEDURE DoAfterLoadOfADat;
+  VAR
+    i:LongWord;
+    txt:Text;
+    temp4:LongWord;
+    temp2:Word;
+    temp1:Byte;
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='M') AND
+          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXMP' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$88,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$89,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$8C,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$8E,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$90,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='A') AND
+          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXAN' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$14,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$16,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$1C,4,@temp4);
+        Write(txt,IntToHex(temp4,8)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+  END;
+
+PROCEDURE TForm1.btn_loadClick(Sender: TObject);
+  VAR i:LongWord;
+  BEGIN
+    fopen.InitialDir:=AppSettings.DatPath;
+    IF fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(fopen.FileName);
+      list_files.Items.Clear;
+      list_extensions.Items.Clear;
+      list_names.Items.Clear;
+      IF LoadDatInfos(fopen.FileName) THEN BEGIN
+        lbl_info.Caption:=
+              '# of files: '+IntToStr(dat_header.Files)+CrLf+
+              '# of named files: '+IntToStr(dat_header.NamedFiles)+CrLf+
+              '# of extensions: '+IntToStr(dat_header.Extensions)+CrLf+
+              'Address of Body: 0x'+IntToHex(dat_header.DataAddr,8)+CrLf+
+              'Address of End: 0x'+IntToHex(dat_header.NamesAddr,8);
+        list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
+        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+          WITH dat_extensionsmap[i] DO BEGIN
+            list_extensions.Items.Add(
+                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
+                FormatNumber(ExtCount,4,' '));{+' (Ident: 0x'+
+                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');}
+          END;
+        END;
+        FOR i:=0 TO dat_header.namedFiles-1 DO BEGIN
+          WITH dat_namedfilesmap[i] DO BEGIN
+            list_names.Items.Add('0x'+IntToHex(filenumber,8)+': 0x'+IntToHex(blubb,8));
+          END;
+        END;
+        Form1.list_extensions.ItemIndex:=0;
+        Form1.list_extensionsClick(Form1);
+        Form1.list_files.ItemIndex:=0;
+        Form1.list_filesDblClick(Form1);
+
+        Form7.RecreateTXMPlist;
+
+        DoAfterLoadOfADat;
+
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    temp:Tdata;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    lbl_fileinfo.Caption:=
+          'Filename: '+dat_files[id].FileName+CrLf+
+          'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
+          'FileType: 0x'+IntToHex(dat_files[id].FileType,8)+CrLf+
+          'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
+    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
+      temp:=LoadDatFile(id);
+      edit_data.Text:=CreateHexString(temp,False);
+      btn_hexcopy.Visible:=True;
+      IF Form5.Visible THEN Form5.ShowPreview(id); 
+    END ELSE BEGIN
+      edit_data.Text:='Zero byte file.'+CrLf+'Oni will take the data for this file of level0_final.dat/raw';
+      btn_hexcopy.Visible:=False;
+    END;
+  END;
+
+PROCEDURE TForm1.FormCreate(Sender: TObject);
+  BEGIN
+    Form1.Caption:='Oni Un/Packer '+version;
+    Form1.FormResize(Form1);
+
+    panel_all.Align:=alClient;
+
+    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;
+
+    //Form1.btn_loadClick(Form1);
+  END;
+
+PROCEDURE TForm1.btn_extractconvertClick(Sender: TObject);
+  VAR
+    result:Integer;
+    id:LongWord;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    IF TComponent(Sender).Name='btn_extract' THEN
+      result:=ExportFile(id,False)
+    ELSE
+      result:=ExportFile(id,True);
+    CASE result OF
+      0{export_noerror}: IF 1=2 THEN BEGIN END;
+      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
+      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
+      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
+    ELSE ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
+    END;
+    Form1.list_files.SetFocus;
+  END;
+
+PROCEDURE TForm1.FormResize(Sender: TObject);
+  CONST
+    MinWidth:Integer=750;
+    MinHeight:Integer=500;
+  BEGIN
+    IF NOT group_progress.Visible THEN BEGIN
+      IF Form1.Width<MinWidth THEN Form1.Width:=MinWidth;
+      IF Form1.Height<MinHeight THEN Form1.Height:=MinHeight;
+    END;
+  END;
+
+PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
+    list_files.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        list_files.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          list_files.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
+  VAR
+    temp:Tdata;
+  BEGIN
+    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
+    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
+  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);
+  END;
+
+PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
+  BEGIN
+    Form1.list_files.Height:=Form1.Splitter1.Top-32;
+    Form1.btn_extractallconvert.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extract.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-33;
+    Form1.btn_extractall.Top:=Form1.Splitter1.Top-33;
+  END;
+
+PROCEDURE TForm1.Splitter2Moved(Sender: TObject);
+  BEGIN
+    Form1.btn_extractall.Left:=Form1.Splitter2.Left-146;
+    Form1.btn_extractallconvert.Left:=Form1.Splitter2.Left-83;
+  END;
+
+PROCEDURE TForm1.btn_extractallconvertClick(Sender: TObject);
+  VAR
+    convert:Boolean;
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    panel_info.Visible:=False;
+    group_progress.Visible:=True;
+    menu.Items.Visible:=False;
+    menu.Items.Enabled:=False;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=103;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=dat_header.files;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    IF TComponent(Sender).Name='btn_extractall' THEN
+      convert:=False
+    ELSE
+      convert:=True;
+    errors:=0;
+    FOR i:=0 TO High(dat_files) DO BEGIN
+      IF ExportFile(i,convert)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+    panel_info.Visible:=True;
+    group_progress.Visible:=False;
+  END;
+
+PROCEDURE TForm1.menu_previewClick(Sender: TObject);
+  BEGIN
+    Form5.Visible:=NOT Form5.Visible;
+  END;
+
+PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
+  BEGIN
+    btn_extractcancel.Caption:='Cancel_';
+  END;
+
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+PROCEDURE TForm1.menu_txmpreplaceClick(Sender: TObject);
+  BEGIN
+    Form7.Visible:=NOT Form7.Visible;
+  END;
+
+END.
Index: /oup/releases/0.14a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.14a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.14a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,205 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, SQLiteTable3, Unit3_data, Unit4_Exporters;
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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>=1024*1024*1024 THEN BEGIN
+      Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB';
+    END ELSE BEGIN
+      IF size>=1024*1024 THEN BEGIN
+        Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB';
+      END ELSE BEGIN
+        IF size>=1024 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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    //ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      //ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.14a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.14a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.14a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,84 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.14a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  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;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.14a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.14a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.14a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,181 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+    {
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+    }
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DAT_'),fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+    {
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.14a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.14a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.14a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,74 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 435
+  Height = 348
+  BorderStyle = bsSizeToolWin
+  Caption = 'Preview'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object img: TImage
+    Left = 0
+    Top = 20
+    Width = 427
+    Height = 304
+    Align = alClient
+  end
+  object panel_buttons: TPanel
+    Left = 0
+    Top = 0
+    Width = 427
+    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
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 72
+    Top = 48
+  end
+end
Index: /oup/releases/0.14a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.14a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.14a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,183 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    img: TImage;
+    timer: TTimer;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    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 FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE ShowPreview(fileid:LongWord);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  memstreams:Array OF TMemoryStream;
+  actualimg:Byte;
+  _fileid:LongWord;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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;
+    Form5.timer.Interval:=Floor(loop_speed*(1/60)*1000);
+    Form5.timer.Enabled:=False;
+    Form5.btn_startstopClick(Form5); 
+    Form5.panel_buttons.Visible:=True;
+  END;
+
+PROCEDURE TForm5.ShowPreview(fileid:LongWord);
+  BEGIN
+    _fileid:=fileid;
+    Form5.timer.Enabled:=False;
+    Form5.panel_buttons.Visible:=False;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[fileid].Extension='TXAN' THEN PreviewTXAN;
+    IF dat_files[fileid].Extension='TXMB' THEN PreviewTXMB;
+    IF dat_files[fileid].Extension='TXMP' THEN PreviewTXMP;
+  END;
+
+PROCEDURE TForm5.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form5.Visible:=False;
+  END;
+
+PROCEDURE TForm5.FormCreate(Sender: TObject);
+  BEGIN
+    SetLength(memstreams,1);
+    memstreams[0]:=TMemoryStream.Create;
+    Form5.Width:=170;
+    Form5.Height:=200;
+  END;
+
+PROCEDURE TForm5.timerTimer(Sender: TObject);
+  BEGIN
+    Inc(actualimg);
+    IF actualimg>=Length(memstreams) THEN actualimg:=0;
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+    Form5.Caption:='Preview '+dat_files[_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
+    Form5.timer.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_dec.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_inc.Enabled:=NOT Form5.timer.Enabled;
+    IF Form5.timer.Enabled THEN
+      Form5.btn_startstop.Caption:='Stop automatic'
+    ELSE
+      Form5.btn_startstop.Caption:='Start automatic';
+  END;
+
+PROCEDURE TForm5.FormResize(Sender: TObject);
+  BEGIN
+    IF Form5.Width>=150 THEN BEGIN
+    END ELSE Form5.Width:=150;
+    IF Form5.Height>=150 THEN BEGIN
+    END ELSE Form5.Height:=150;
+  END;
+
+PROCEDURE TForm5.btn_decClick(Sender: TObject);
+  BEGIN
+    IF actualimg>0 THEN
+      Dec(actualimg)
+    ELSE
+      actualimg:=High(memstreams);
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.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;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+END.
Index: /oup/releases/0.14a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.14a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.14a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,398 @@
+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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,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.14a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.14a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.14a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,161 @@
+object Form7: TForm7
+  Left = 0
+  Top = 0
+  Width = 400
+  Height = 453
+  BorderStyle = bsSizeToolWin
+  Caption = 'TXMP Replacer'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_12: TPanel
+    Left = 0
+    Top = 0
+    Width = 392
+    Height = 350
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter1: TSplitter
+      Left = 200
+      Top = 0
+      Width = 8
+      Height = 350
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object group_txmpselect: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 200
+      Height = 350
+      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 = 150
+        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
+    end
+    object group_bmpselect: TGroupBox
+      Left = 208
+      Top = 0
+      Width = 184
+      Height = 350
+      Align = alClient
+      Caption = '2. Open BMP to replace with'
+      Enabled = False
+      TabOrder = 1
+      object image_bmppreview: TImage
+        Left = 2
+        Top = 45
+        Width = 180
+        Height = 303
+        Align = alClient
+      end
+      object panel_load: TPanel
+        Left = 2
+        Top = 15
+        Width = 180
+        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 = 350
+    Width = 392
+    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
+end
Index: /oup/releases/0.14a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.14a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.14a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,219 @@
+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;
+    image_txmppreview: TImage;
+    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;
+    PROCEDURE btn_replaceClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+    PROCEDURE list_txmpClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE RecreateTXMPlist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit6_imgfuncs;
+{$R *.dfm}
+VAR
+  actual_bmpdata:Tdata;
+
+PROCEDURE TForm7.RecreateTXMPlist;
+  VAR
+    i:LongWord;
+  BEGIN
+    Form7.list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        Form7.list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    Form7.group_bmpselect.Enabled:=False;
+    //Form7.image_txmppreview.Picture.Free;
+    //Form7.image_txmppreview.Picture.Create;
+    Form7.check_transparency.Checked:=False;
+    Form7.check_fading.Checked:=False;
+  END;
+
+PROCEDURE TForm7.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form7.Visible:=False;
+  END;
+
+PROCEDURE TForm7.FormResize(Sender: TObject);
+  BEGIN
+    IF Form7.Width>=400 THEN BEGIN
+    END ELSE Form7.Width:=400;
+    IF Form7.Height>=350 THEN BEGIN
+    END ELSE Form7.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);
+    Form7.check_fading.Checked:=(fadingbyte AND $01)>0;
+    Form7.check_transparency.Checked:=(depthbyte AND $04)>0;
+    Form7.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);
+    Form7.image_txmppreview.Picture.Bitmap.LoadFromStream(mem);
+    mem.Free;
+
+    Form7.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);
+      Form7.image_bmppreview.Picture.Bitmap.LoadFromStream(mem);
+      mem.Free;
+
+      Form7.group_options.Enabled:=True;
+    END;
+  END;
+
+PROCEDURE TForm7.btn_replaceClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    imgpkg:TImgPackage;
+    rawfile:TFileStream;
+    datfile:TFileStream;
+    dataddr:LongWord;
+    old_rawaddr,new_rawaddr:LongWord;
+    oldwidth,oldheight:Word;
+    oldstore,olddepth,oldfading:Byte;
+    oldsize:LongWord;
+    newsize:LongWord;
+    datword,datbyte:Word;
+  BEGIN
+    IF Form7.list_txmp.ItemIndex>=0 THEN BEGIN
+      imgpkg:=BmpToImgdata(actual_bmpdata,check_32bit.Checked);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Read(oldfading,1);
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Read(olddepth,1);
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Read(oldstore,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Read(old_rawaddr,4);
+      IF (oldwidth<>imgpkg.imgx) OR (oldheight<>imgpkg.imgy) THEN BEGIN
+        IF MessageBox(Form7.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,Form7.check_fading.Checked)
+      ELSE
+        newsize:=GetImageDataSize(imgpkg.imgx,imgpkg.imgy,16,Form7.check_fading.Checked);
+
+      IF newsize<=oldsize THEN
+        new_rawaddr:=old_rawaddr
+      ELSE
+        new_rawaddr:=rawfile.Size;
+
+      datbyte:=$00;
+      IF Form7.check_fading.Checked THEN datbyte:=datbyte OR $01;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datbyte,2);
+      datbyte:=$10;
+      IF Form7.check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Write(datbyte,2);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datbyte,2);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      IF Form7.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;
+
+END.
Index: /oup/releases/0.15a/_changelog.txt
===================================================================
--- /oup/releases/0.15a/_changelog.txt	(revision 8)
+++ /oup/releases/0.15a/_changelog.txt	(revision 8)
@@ -0,0 +1,20 @@
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.15a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.15a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.15a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.15a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.15a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.15a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,15 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.15a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.15a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.15a/src/OniUnPacker.cfg	(revision 8)
@@ -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.15a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.15a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.15a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,23 @@
+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};
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm5, Form5);
+  Application.CreateForm(TForm7, Form7);
+  Application.CreateForm(TForm8, Form8);
+  Application.Run;
+END.
Index: /oup/releases/0.15a/src/SQLite3.pas
===================================================================
--- /oup/releases/0.15a/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.15a/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.15a/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.15a/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.15a/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,883 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.15a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.15a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.15a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,261 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 582
+  ClientWidth = 692
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = menu
+  OldCreateOrder = False
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_all: TPanel
+    Left = 0
+    Top = 100
+    Width = 692
+    Height = 300
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter2: TSplitter
+      Left = 360
+      Top = 0
+      Width = 8
+      Height = 300
+      AutoSnap = False
+      Beveled = True
+      MinSize = 360
+    end
+    object panel_left: TPanel
+      Left = 0
+      Top = 0
+      Width = 360
+      Height = 300
+      Cursor = crDrag
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object Splitter1: TSplitter
+        Left = 0
+        Top = 241
+        Width = 360
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+        OnMoved = Splitter1Moved
+      end
+      object panel_files: TPanel
+        Left = 0
+        Top = 0
+        Width = 360
+        Height = 241
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_extractconvert: TButton
+          Left = 1
+          Top = 220
+          Width = 358
+          Height = 20
+          Caption = 'Convert and extract file'
+          Enabled = False
+          TabOrder = 0
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object list_files: TListBox
+          Left = 0
+          Top = 0
+          Width = 360
+          Height = 218
+          Align = alTop
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Fixedsys'
+          Font.Style = []
+          ItemHeight = 15
+          ParentFont = False
+          TabOrder = 1
+          OnClick = list_filesDblClick
+          OnDblClick = list_filesDblClick
+        end
+      end
+      object list_extensions: TListBox
+        Left = 0
+        Top = 249
+        Width = 360
+        Height = 51
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+        OnClick = list_extensionsClick
+        OnDblClick = list_extensionsClick
+      end
+    end
+    object panel_file: TPanel
+      Left = 368
+      Top = 0
+      Width = 324
+      Height = 300
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 1
+      object lbl_fileinfo: TLabel
+        Left = 0
+        Top = 0
+        Width = 324
+        Height = 49
+        Align = alTop
+        AutoSize = False
+      end
+      object edit_data: TMemo
+        Left = 0
+        Top = 49
+        Width = 324
+        Height = 251
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -13
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ParentFont = False
+        ReadOnly = True
+        ScrollBars = ssVertical
+        TabOrder = 0
+        WordWrap = False
+      end
+    end
+  end
+  object group_progress: TGroupBox
+    Left = 296
+    Top = 480
+    Width = 297
+    Height = 57
+    Caption = 'Extracting...'
+    TabOrder = 1
+    Visible = False
+    object lbl_progress: TLabel
+      Left = 10
+      Top = 36
+      Width = 279
+      Height = 18
+      AutoSize = False
+    end
+    object progress: TProgressBar
+      Left = 8
+      Top = 16
+      Width = 217
+      Height = 17
+      Step = 1
+      TabOrder = 0
+    end
+    object btn_extractcancel: TButton
+      Left = 232
+      Top = 16
+      Width = 57
+      Height = 33
+      Caption = 'Cancel'
+      TabOrder = 1
+      OnClick = btn_extractcancelClick
+    end
+  end
+  object statbar: TStatusBar
+    Left = 0
+    Top = 565
+    Width = 692
+    Height = 17
+    BiDiMode = bdLeftToRight
+    Panels = <
+      item
+        Text = 'Current .dat: -'
+        Width = 500
+      end
+      item
+        Text = 'Files: -'
+        Width = 90
+      end
+      item
+        Text = 'Extensions: -'
+        Width = 100
+      end>
+    ParentBiDiMode = False
+  end
+  object fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    Left = 64
+    Top = 120
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 224
+    object menu_main: TMenuItem
+      Caption = '&Main'
+      object menu_loaddat: TMenuItem
+        Caption = '&Select .dat-file ...'
+        OnClick = menu_loaddatClick
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_extract: TMenuItem
+      Caption = '&Extract/Convert'
+      Enabled = False
+      object menu_extractfile: TMenuItem
+        Caption = 'Convert and extract current &file'
+        OnClick = menu_extractfileClick
+      end
+      object menu_extractlist: TMenuItem
+        Caption = 'Convert and extract all files currently in &list'
+        OnClick = menu_extractlistClick
+      end
+      object menu_extractall: TMenuItem
+        Caption = 'Convert and extract &all files'
+        OnClick = menu_extractallClick
+      end
+    end
+    object menu_tools: TMenuItem
+      Caption = '&Tools'
+      Enabled = False
+      object menu_preview: TMenuItem
+        Caption = '&Preview Window ...'
+        OnClick = menu_previewClick
+      end
+      object menu_binedit: TMenuItem
+        Caption = '&Binary .dat editor ...'
+        Enabled = False
+        OnClick = menu_bineditClick
+      end
+      object menu_txmpreplace: TMenuItem
+        Caption = '&TXMP replacer ...'
+        OnClick = menu_txmpreplaceClick
+      end
+    end
+  end
+end
Index: /oup/releases/0.15a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.15a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.15a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,427 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace, Unit8_binedit;
+
+TYPE
+  TForm1 = Class(TForm)
+    panel_all: TPanel;
+    panel_left: TPanel;
+    Splitter1: TSplitter;
+    panel_files: TPanel;
+    btn_extractconvert: TButton;
+    list_files: TListBox;
+    list_extensions: TListBox;
+    Splitter2: TSplitter;
+    fopen: TOpenDialog;
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    btn_extractcancel: TButton;
+    menu_tools: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    menu_extract: TMenuItem;
+    menu_extractfile: TMenuItem;
+    menu_extractlist: TMenuItem;
+    menu_extractall: TMenuItem;
+    menu_loaddat: TMenuItem;
+    menu_sep1: TMenuItem;
+    menu_binedit: TMenuItem;
+    statbar: TStatusBar;
+    panel_file: TPanel;
+    edit_data: TMemo;
+    lbl_fileinfo: TLabel;
+    PROCEDURE menu_extractallClick(Sender: TObject);
+    PROCEDURE menu_extractlistClick(Sender: TObject);
+    PROCEDURE menu_extractfileClick(Sender: TObject);
+    PROCEDURE menu_bineditClick(Sender: TObject);
+    PROCEDURE menu_loaddatClick(Sender: TObject);
+    PROCEDURE menu_txmpreplaceClick(Sender: TObject);
+    PROCEDURE menu_exitClick(Sender: TObject);
+    PROCEDURE btn_extractcancelClick(Sender: TObject);
+    PROCEDURE menu_previewClick(Sender: TObject);
+    PROCEDURE Splitter1Moved(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE btn_hexcopyClick(Sender: TObject);
+    PROCEDURE list_extensionsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE btn_extractconvertClick(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE list_filesDblClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form1: TForm1;
+
+IMPLEMENTATION
+{$R *.dfm}
+
+PROCEDURE DoAfterLoadOfADat;
+  VAR
+    i:LongWord;
+    txt:Text;
+    temp4:LongWord;
+    temp2:Word;
+    temp1:Byte;
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='M') AND
+          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXMP' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$88,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$89,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$8C,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$8E,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$90,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='A') AND
+          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXAN' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$14,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$16,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$1C,4,@temp4);
+        Write(txt,IntToHex(temp4,8)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+  END;
+
+PROCEDURE LoadDat;
+  VAR i:LongWord;
+  BEGIN
+    Form1.fopen.InitialDir:=AppSettings.DatPath;
+    IF Form1.fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(Form1.fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(Form1.fopen.FileName);
+      Form1.list_files.Items.Clear;
+      Form1.list_extensions.Items.Clear;
+      IF LoadDatInfos(Form1.fopen.FileName) THEN BEGIN
+        Form1.list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
+        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+          WITH dat_extensionsmap[i] DO BEGIN
+            Form1.list_extensions.Items.Add(
+                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
+                FormatNumber(ExtCount,4,' '));{+' (Ident: 0x'+
+                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');}
+          END;
+        END;
+        Form1.list_extensions.ItemIndex:=0;
+        Form1.list_extensionsClick(Form1);
+        Form1.list_files.ItemIndex:=0;
+        Form1.list_filesDblClick(Form1);
+        Form1.statbar.Panels.Items[0].Text:='Current .dat: '+dat_FileName;
+        Form1.statbar.Panels.Items[1].Text:='Files: '+IntToStr(dat_header.Files);
+        Form1.statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(dat_header.Extensions);
+        Form1.menu_tools.Enabled:=True;
+        Form1.menu_extract.Enabled:=True;
+        Form1.btn_extractconvert.Enabled:=True;
+
+        Form7.RecreateTXMPlist;
+
+        DoAfterLoadOfADat;
+
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+Form1.fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+PROCEDURE TForm1.btn_loadClick(Sender: TObject);
+  BEGIN
+    LoadDat;
+  END;
+
+PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    temp:Tdata;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    lbl_fileinfo.Caption:=
+          'Filename: '+dat_files[id].FileName+CrLf+
+          'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
+          'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
+    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
+      temp:=LoadDatFile(id);
+      edit_data.Text:=CreateHexString(temp,False);
+      Form5.ShowPreview(id);
+    END ELSE BEGIN
+      edit_data.Text:='Zero byte file.'+CrLf+'Oni will take the data for this file of level0_final.dat/raw';
+    END;
+  END;
+
+PROCEDURE TForm1.FormCreate(Sender: TObject);
+  BEGIN
+    Form1.Caption:='Oni Un/Packer '+version;
+    Form1.FormResize(Form1);
+
+    panel_all.Align:=alClient;
+
+    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.btn_extractconvertClick(Sender: TObject);
+  BEGIN
+    Form1.menu_extractfileClick(Form1);
+  END;
+
+PROCEDURE TForm1.FormResize(Sender: TObject);
+  CONST
+    MinWidth:Integer=750;
+    MinHeight:Integer=500;
+  BEGIN
+    IF NOT group_progress.Visible THEN 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 ELSE BEGIN
+      Form1.Width:=400;
+      Form1.Height:=120;
+    END;
+  END;
+
+PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
+    list_files.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        list_files.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          list_files.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
+  VAR
+    temp:Tdata;
+  BEGIN
+    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
+    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
+  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);
+  END;
+
+PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
+  BEGIN
+    Form1.list_files.Height:=Form1.Splitter1.Top-23;
+    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-21;
+  END;
+
+PROCEDURE TForm1.menu_previewClick(Sender: TObject);
+  BEGIN
+    Form5.Visible:=NOT Form5.Visible;
+  END;
+
+PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
+  BEGIN
+    btn_extractcancel.Caption:='Cancel_';
+  END;
+
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+PROCEDURE TForm1.menu_txmpreplaceClick(Sender: TObject);
+  BEGIN
+    Form7.Visible:=NOT Form7.Visible;
+  END;
+
+PROCEDURE TForm1.menu_loaddatClick(Sender: TObject);
+  BEGIN
+    LoadDat;
+  END;
+
+PROCEDURE TForm1.menu_bineditClick(Sender: TObject);
+  BEGIN
+    Form8.Visible:=NOT Form8.Visible;
+  END;
+
+PROCEDURE TForm1.menu_extractfileClick(Sender: TObject);
+  VAR
+    result:Integer;
+    id:LongWord;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    result:=ExportFile(id,True);
+    CASE result OF
+      0{export_noerror}: BEGIN END;
+      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
+      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
+      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
+    ELSE
+      ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
+    END;
+    Form1.list_files.SetFocus;
+  END;
+
+PROCEDURE TForm1.menu_extractlistClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    group_progress.Visible:=True;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=120;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=list_files.Items.Count;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    errors:=0;
+    FOR i:=0 TO progress.Max-1 DO BEGIN
+      IF ExportFile(StrToInt(MidStr(list_files.Items.Strings[i],1,5)),True)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(progress.Max);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    group_progress.Visible:=False;
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+  END;
+
+PROCEDURE TForm1.menu_extractallClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    group_progress.Visible:=True;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=120;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=dat_header.files;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    errors:=0;
+    FOR i:=0 TO High(dat_files) DO BEGIN
+      IF ExportFile(i,True)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    group_progress.Visible:=False;
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+  END;
+
+END.
Index: /oup/releases/0.15a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.15a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.15a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,205 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, SQLiteTable3, Unit3_data, Unit4_Exporters;
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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>=1024*1024*1024 THEN BEGIN
+      Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB';
+    END ELSE BEGIN
+      IF size>=1024*1024 THEN BEGIN
+        Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB';
+      END ELSE BEGIN
+        IF size>=1024 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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    //ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      //ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.15a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.15a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.15a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,84 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.15a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  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;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.15a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.15a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.15a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,181 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+    {
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+    }
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DAT_'),fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+    {
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.15a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.15a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.15a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,74 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 435
+  Height = 348
+  BorderStyle = bsSizeToolWin
+  Caption = 'Preview'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object img: TImage
+    Left = 0
+    Top = 20
+    Width = 427
+    Height = 304
+    Align = alClient
+  end
+  object panel_buttons: TPanel
+    Left = 0
+    Top = 0
+    Width = 427
+    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
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 72
+    Top = 48
+  end
+end
Index: /oup/releases/0.15a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.15a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.15a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,183 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    img: TImage;
+    timer: TTimer;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    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 FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE ShowPreview(fileid:LongWord);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  memstreams:Array OF TMemoryStream;
+  actualimg:Byte;
+  _fileid:LongWord;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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;
+    Form5.timer.Interval:=Floor(loop_speed*(1/60)*1000);
+    Form5.timer.Enabled:=False;
+    Form5.btn_startstopClick(Form5); 
+    Form5.panel_buttons.Visible:=True;
+  END;
+
+PROCEDURE TForm5.ShowPreview(fileid:LongWord);
+  BEGIN
+    _fileid:=fileid;
+    Form5.timer.Enabled:=False;
+    Form5.panel_buttons.Visible:=False;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[fileid].Extension='TXAN' THEN PreviewTXAN;
+    IF dat_files[fileid].Extension='TXMB' THEN PreviewTXMB;
+    IF dat_files[fileid].Extension='TXMP' THEN PreviewTXMP;
+  END;
+
+PROCEDURE TForm5.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form5.Visible:=False;
+  END;
+
+PROCEDURE TForm5.FormCreate(Sender: TObject);
+  BEGIN
+    SetLength(memstreams,1);
+    memstreams[0]:=TMemoryStream.Create;
+    Form5.Width:=260;
+    Form5.Height:=300;
+  END;
+
+PROCEDURE TForm5.timerTimer(Sender: TObject);
+  BEGIN
+    Inc(actualimg);
+    IF actualimg>=Length(memstreams) THEN actualimg:=0;
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+    Form5.Caption:='Preview '+dat_files[_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
+    Form5.timer.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_dec.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_inc.Enabled:=NOT Form5.timer.Enabled;
+    IF Form5.timer.Enabled THEN
+      Form5.btn_startstop.Caption:='Stop automatic'
+    ELSE
+      Form5.btn_startstop.Caption:='Start automatic';
+  END;
+
+PROCEDURE TForm5.FormResize(Sender: TObject);
+  BEGIN
+    IF Form5.Width>=150 THEN BEGIN
+    END ELSE Form5.Width:=150;
+    IF Form5.Height>=150 THEN BEGIN
+    END ELSE Form5.Height:=150;
+  END;
+
+PROCEDURE TForm5.btn_decClick(Sender: TObject);
+  BEGIN
+    IF actualimg>0 THEN
+      Dec(actualimg)
+    ELSE
+      actualimg:=High(memstreams);
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.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;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+END.
Index: /oup/releases/0.15a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.15a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.15a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,398 @@
+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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,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.15a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.15a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.15a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,161 @@
+object Form7: TForm7
+  Left = 0
+  Top = 0
+  Width = 400
+  Height = 453
+  BorderStyle = bsSizeToolWin
+  Caption = 'TXMP Replacer'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_12: TPanel
+    Left = 0
+    Top = 0
+    Width = 392
+    Height = 350
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter1: TSplitter
+      Left = 200
+      Top = 0
+      Width = 8
+      Height = 350
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object group_txmpselect: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 200
+      Height = 350
+      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 = 150
+        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
+    end
+    object group_bmpselect: TGroupBox
+      Left = 208
+      Top = 0
+      Width = 184
+      Height = 350
+      Align = alClient
+      Caption = '2. Open BMP to replace with'
+      Enabled = False
+      TabOrder = 1
+      object image_bmppreview: TImage
+        Left = 2
+        Top = 45
+        Width = 180
+        Height = 303
+        Align = alClient
+      end
+      object panel_load: TPanel
+        Left = 2
+        Top = 15
+        Width = 180
+        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 = 350
+    Width = 392
+    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
+end
Index: /oup/releases/0.15a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.15a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.15a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,219 @@
+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;
+    image_txmppreview: TImage;
+    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;
+    PROCEDURE btn_replaceClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+    PROCEDURE list_txmpClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE RecreateTXMPlist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit6_imgfuncs;
+{$R *.dfm}
+VAR
+  actual_bmpdata:Tdata;
+
+PROCEDURE TForm7.RecreateTXMPlist;
+  VAR
+    i:LongWord;
+  BEGIN
+    Form7.list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        Form7.list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    Form7.group_bmpselect.Enabled:=False;
+    //Form7.image_txmppreview.Picture.Free;
+    //Form7.image_txmppreview.Picture.Create;
+    Form7.check_transparency.Checked:=False;
+    Form7.check_fading.Checked:=False;
+  END;
+
+PROCEDURE TForm7.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form7.Visible:=False;
+  END;
+
+PROCEDURE TForm7.FormResize(Sender: TObject);
+  BEGIN
+    IF Form7.Width>=400 THEN BEGIN
+    END ELSE Form7.Width:=400;
+    IF Form7.Height>=350 THEN BEGIN
+    END ELSE Form7.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);
+    Form7.check_fading.Checked:=(fadingbyte AND $01)>0;
+    Form7.check_transparency.Checked:=(depthbyte AND $04)>0;
+    Form7.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);
+    Form7.image_txmppreview.Picture.Bitmap.LoadFromStream(mem);
+    mem.Free;
+
+    Form7.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);
+      Form7.image_bmppreview.Picture.Bitmap.LoadFromStream(mem);
+      mem.Free;
+
+      Form7.group_options.Enabled:=True;
+    END;
+  END;
+
+PROCEDURE TForm7.btn_replaceClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    imgpkg:TImgPackage;
+    rawfile:TFileStream;
+    datfile:TFileStream;
+    dataddr:LongWord;
+    old_rawaddr,new_rawaddr:LongWord;
+    oldwidth,oldheight:Word;
+    oldstore,olddepth,oldfading:Byte;
+    oldsize:LongWord;
+    newsize:LongWord;
+    datword,datbyte:Word;
+  BEGIN
+    IF Form7.list_txmp.ItemIndex>=0 THEN BEGIN
+      imgpkg:=BmpToImgdata(actual_bmpdata,check_32bit.Checked);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Read(oldfading,1);
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Read(olddepth,1);
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Read(oldstore,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Read(old_rawaddr,4);
+      IF (oldwidth<>imgpkg.imgx) OR (oldheight<>imgpkg.imgy) THEN BEGIN
+        IF MessageBox(Form7.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,Form7.check_fading.Checked)
+      ELSE
+        newsize:=GetImageDataSize(imgpkg.imgx,imgpkg.imgy,16,Form7.check_fading.Checked);
+
+      IF newsize<=oldsize THEN
+        new_rawaddr:=old_rawaddr
+      ELSE
+        new_rawaddr:=rawfile.Size;
+
+      datbyte:=$00;
+      IF Form7.check_fading.Checked THEN datbyte:=datbyte OR $01;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datbyte,2);
+      datbyte:=$10;
+      IF Form7.check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Write(datbyte,2);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datbyte,2);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      IF Form7.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;
+
+END.
Index: /oup/releases/0.15a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.15a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.15a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,51 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  AutoScroll = False
+  BorderStyle = bsSizeToolWin
+  Caption = 'Form8'
+  ClientHeight = 617
+  ClientWidth = 698
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  PixelsPerInch = 96
+  TextHeight = 13
+  object grid: TWrapGrid
+    Left = 136
+    Top = 8
+    Width = 561
+    Height = 273
+    BevelInner = bvNone
+    BevelOuter = bvNone
+    ColCount = 18
+    DefaultColWidth = 22
+    DefaultRowHeight = 18
+    FixedColor = clWindow
+    RowCount = 1
+    FixedRows = 0
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -11
+    Font.Name = 'Fixedsys'
+    Font.Style = []
+    Options = [goEditing]
+    ParentFont = False
+    ScrollBars = ssVertical
+    TabOrder = 0
+  end
+  object ListBox1: TListBox
+    Left = 0
+    Top = 296
+    Width = 161
+    Height = 313
+    ItemHeight = 13
+    TabOrder = 1
+  end
+end
Index: /oup/releases/0.15a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.15a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.15a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,44 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Grids, Wrapgrid, StdCtrls;
+
+TYPE
+  TForm8 = Class(TForm)
+    grid: TWrapGrid;
+    ListBox1: TListBox;
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+
+PROCEDURE TForm8.FormCreate(Sender: TObject);
+  BEGIN
+    grid.RowCount:=1;
+    grid.ColCount:=18;
+    grid.FixedCols:=1;
+    grid.FixedRows:=0;
+
+    grid.Cells[0,0]:='0x000000';
+    grid.ColWidths[0]:=80;
+    grid.ColWidths[17]:=140;
+    grid.Cells[1,0]:='00';
+    grid.Cells[2,0]:='FF';
+    grid.Cells[17,0]:='..##############';
+  END;
+
+PROCEDURE TForm8.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form8.Visible:=False;
+  END;
+
+END.
Index: /oup/releases/0.16a/_changelog.txt
===================================================================
--- /oup/releases/0.16a/_changelog.txt	(revision 8)
+++ /oup/releases/0.16a/_changelog.txt	(revision 8)
@@ -0,0 +1,25 @@
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.16a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.16a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.16a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.16a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.16a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.16a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,15 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.16a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.16a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.16a/src/OniUnPacker.cfg	(revision 8)
@@ -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.16a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.16a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.16a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,23 @@
+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};
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm5, Form5);
+  Application.CreateForm(TForm7, Form7);
+  Application.CreateForm(TForm8, Form8);
+  Application.Run;
+END.
Index: /oup/releases/0.16a/src/SQLite3.pas
===================================================================
--- /oup/releases/0.16a/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.16a/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.16a/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.16a/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.16a/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,883 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.16a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.16a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.16a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,297 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 563
+  ClientWidth = 692
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = menu
+  OldCreateOrder = False
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_all: TPanel
+    Left = 0
+    Top = 100
+    Width = 692
+    Height = 300
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter2: TSplitter
+      Left = 360
+      Top = 0
+      Width = 8
+      Height = 300
+      AutoSnap = False
+      Beveled = True
+      MinSize = 360
+    end
+    object panel_left: TPanel
+      Left = 0
+      Top = 0
+      Width = 360
+      Height = 300
+      Cursor = crDrag
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object Splitter1: TSplitter
+        Left = 0
+        Top = 241
+        Width = 360
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+        OnMoved = Splitter1Moved
+      end
+      object panel_files: TPanel
+        Left = 0
+        Top = 0
+        Width = 360
+        Height = 241
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_extractconvert: TButton
+          Left = 1
+          Top = 220
+          Width = 358
+          Height = 20
+          Caption = 'Convert and extract file'
+          Enabled = False
+          TabOrder = 0
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object list_files: TListBox
+          Left = 0
+          Top = 0
+          Width = 360
+          Height = 218
+          Align = alTop
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Fixedsys'
+          Font.Style = []
+          ItemHeight = 15
+          ParentFont = False
+          TabOrder = 1
+          OnClick = list_filesDblClick
+          OnDblClick = list_filesDblClick
+        end
+      end
+      object list_extensions: TListBox
+        Left = 0
+        Top = 249
+        Width = 360
+        Height = 51
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+        OnClick = list_extensionsClick
+        OnDblClick = list_extensionsClick
+      end
+    end
+    object panel_file: TPanel
+      Left = 368
+      Top = 0
+      Width = 324
+      Height = 300
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 1
+      object lbl_fileinfo: TLabel
+        Left = 0
+        Top = 0
+        Width = 324
+        Height = 44
+        Align = alTop
+        AutoSize = False
+      end
+      object lbl_zerobyte: TLabel
+        Left = 32
+        Top = 136
+        Width = 265
+        Height = 41
+        AutoSize = False
+        Caption = 
+          'Zero byte file. Oni will take the data for this file of level0_f' +
+          'inal.dat/raw'
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -16
+        Font.Name = 'Tahoma'
+        Font.Style = []
+        ParentFont = False
+        Visible = False
+        WordWrap = True
+      end
+      object hex: TMPHexEditor
+        Left = 0
+        Top = 44
+        Width = 324
+        Height = 256
+        Cursor = crIBeam
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -16
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ParentFont = False
+        TabOrder = 0
+        BytesPerRow = 16
+        Translation = tkAsIs
+        OffsetFormat = '6!10:0x|'
+        Colors.Background = clWindow
+        Colors.ChangedBackground = clWhite
+        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 = False
+        AllowInsertMode = False
+        DrawGridLines = False
+        ReadOnlyView = True
+        Version = 'May 23, 2005; '#169' markus stephany, vcl[at]mirkes[dot]de'
+      end
+    end
+  end
+  object group_progress: TGroupBox
+    Left = 296
+    Top = 480
+    Width = 297
+    Height = 57
+    Caption = 'Extracting...'
+    TabOrder = 1
+    Visible = False
+    object lbl_progress: TLabel
+      Left = 10
+      Top = 36
+      Width = 279
+      Height = 18
+      AutoSize = False
+    end
+    object progress: TProgressBar
+      Left = 8
+      Top = 16
+      Width = 217
+      Height = 17
+      Step = 1
+      TabOrder = 0
+    end
+    object btn_extractcancel: TButton
+      Left = 232
+      Top = 16
+      Width = 57
+      Height = 33
+      Caption = 'Cancel'
+      TabOrder = 1
+      OnClick = btn_extractcancelClick
+    end
+  end
+  object statbar: TStatusBar
+    Left = 0
+    Top = 546
+    Width = 692
+    Height = 17
+    BiDiMode = bdLeftToRight
+    Panels = <
+      item
+        Text = 'Current .dat: -'
+        Width = 500
+      end
+      item
+        Text = 'Files: -'
+        Width = 90
+      end
+      item
+        Text = 'Extensions: -'
+        Width = 100
+      end>
+    ParentBiDiMode = False
+  end
+  object fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    Left = 64
+    Top = 120
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 224
+    object menu_main: TMenuItem
+      Caption = '&Main'
+      object menu_loaddat: TMenuItem
+        Caption = '&Select .dat-file ...'
+        OnClick = menu_loaddatClick
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_extract: TMenuItem
+      Caption = '&Extract/Convert'
+      Enabled = False
+      object menu_extractfile: TMenuItem
+        Caption = 'Convert and extract current &file'
+        OnClick = menu_extractfileClick
+      end
+      object menu_extractlist: TMenuItem
+        Caption = 'Convert and extract all files currently in &list'
+        OnClick = menu_extractlistClick
+      end
+      object menu_extractall: TMenuItem
+        Caption = 'Convert and extract &all files'
+        OnClick = menu_extractallClick
+      end
+    end
+    object menu_tools: TMenuItem
+      Caption = '&Tools'
+      Enabled = False
+      object menu_preview: TMenuItem
+        Caption = '&Preview Window ...'
+        OnClick = menu_previewClick
+      end
+      object menu_binedit: TMenuItem
+        Caption = '&Binary .dat editor ...'
+        OnClick = menu_bineditClick
+      end
+      object menu_txmpreplace: TMenuItem
+        Caption = '&TXMP replacer ...'
+        OnClick = menu_txmpreplaceClick
+      end
+    end
+  end
+end
Index: /oup/releases/0.16a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.16a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.16a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,439 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace, Unit8_binedit,
+  Grids, MPHexEditor;
+
+TYPE
+  TForm1 = Class(TForm)
+    panel_all: TPanel;
+    panel_left: TPanel;
+    Splitter1: TSplitter;
+    panel_files: TPanel;
+    btn_extractconvert: TButton;
+    list_files: TListBox;
+    list_extensions: TListBox;
+    Splitter2: TSplitter;
+    fopen: TOpenDialog;
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    btn_extractcancel: TButton;
+    menu_tools: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    menu_extract: TMenuItem;
+    menu_extractfile: TMenuItem;
+    menu_extractlist: TMenuItem;
+    menu_extractall: TMenuItem;
+    menu_loaddat: TMenuItem;
+    menu_sep1: TMenuItem;
+    menu_binedit: TMenuItem;
+    statbar: TStatusBar;
+    panel_file: TPanel;
+    lbl_fileinfo: TLabel;
+    hex: TMPHexEditor;
+    lbl_zerobyte: TLabel;
+    PROCEDURE menu_extractallClick(Sender: TObject);
+    PROCEDURE menu_extractlistClick(Sender: TObject);
+    PROCEDURE menu_extractfileClick(Sender: TObject);
+    PROCEDURE menu_bineditClick(Sender: TObject);
+    PROCEDURE menu_loaddatClick(Sender: TObject);
+    PROCEDURE menu_txmpreplaceClick(Sender: TObject);
+    PROCEDURE menu_exitClick(Sender: TObject);
+    PROCEDURE btn_extractcancelClick(Sender: TObject);
+    PROCEDURE menu_previewClick(Sender: TObject);
+    PROCEDURE Splitter1Moved(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE btn_hexcopyClick(Sender: TObject);
+    PROCEDURE list_extensionsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE btn_extractconvertClick(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE list_filesDblClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form1: TForm1;
+
+IMPLEMENTATION
+{$R *.dfm}
+
+PROCEDURE DoAfterLoadOfADat;
+  VAR
+    i:LongWord;
+    txt:Text;
+    temp4:LongWord;
+    temp2:Word;
+    temp1:Byte;
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='M') AND
+          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXMP' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$88,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$89,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$8C,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$8E,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$90,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='A') AND
+          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXAN' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$14,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$16,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$1C,4,@temp4);
+        Write(txt,IntToHex(temp4,8)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+  END;
+
+PROCEDURE LoadDat;
+  VAR i:LongWord;
+  BEGIN
+    Form1.fopen.InitialDir:=AppSettings.DatPath;
+    IF Form1.fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(Form1.fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(Form1.fopen.FileName);
+      Form1.list_files.Items.Clear;
+      Form1.list_extensions.Items.Clear;
+      IF LoadDatInfos(Form1.fopen.FileName) THEN BEGIN
+        Form1.list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
+        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+          WITH dat_extensionsmap[i] DO BEGIN
+            Form1.list_extensions.Items.Add(
+                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
+                FormatNumber(ExtCount,4,' '));{+' (Ident: 0x'+
+                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');}
+          END;
+        END;
+        Form1.list_extensions.ItemIndex:=0;
+        Form1.list_extensionsClick(Form1);
+        Form1.list_files.ItemIndex:=0;
+        Form1.list_filesDblClick(Form1);
+        Form1.statbar.Panels.Items[0].Text:='Current .dat: '+dat_FileName;
+        Form1.statbar.Panels.Items[1].Text:='Files: '+IntToStr(dat_header.Files);
+        Form1.statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(dat_header.Extensions);
+        Form1.menu_tools.Enabled:=True;
+        Form1.menu_extract.Enabled:=True;
+        Form1.btn_extractconvert.Enabled:=True;
+
+        Form7.RecreateTXMPlist;
+        Form8.Recreatelist;
+
+        DoAfterLoadOfADat;
+
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+Form1.fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+PROCEDURE TForm1.btn_loadClick(Sender: TObject);
+  BEGIN
+    LoadDat;
+  END;
+
+PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    temp:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
+      lbl_fileinfo.Caption:=
+            'Filename: '+dat_files[id].FileName+CrLf+
+            'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
+            'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
+      temp:=LoadDatFile(id);
+      mem:=TMemoryStream.Create;
+      mem.Write(temp[0],Length(temp));
+      hex.LoadFromStream(mem);
+      mem.Free;
+      Form5.ShowPreview(id);
+      lbl_zerobyte.Visible:=False;
+      hex.Visible:=True;
+    END ELSE BEGIN
+      lbl_fileinfo.Caption:=
+            'Filename: '+dat_files[id].FileName;
+      lbl_zerobyte.Visible:=True;
+      hex.Visible:=False;
+    END;
+  END;
+
+PROCEDURE TForm1.FormCreate(Sender: TObject);
+  BEGIN
+    Form1.Caption:='Oni Un/Packer '+version;
+    Form1.FormResize(Form1);
+
+    panel_all.Align:=alClient;
+
+    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.btn_extractconvertClick(Sender: TObject);
+  BEGIN
+    Form1.menu_extractfileClick(Form1);
+  END;
+
+PROCEDURE TForm1.FormResize(Sender: TObject);
+  CONST
+    MinWidth:Integer=750;
+    MinHeight:Integer=500;
+  BEGIN
+    IF NOT group_progress.Visible THEN 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 ELSE BEGIN
+      Form1.Width:=400;
+      Form1.Height:=120;
+    END;
+  END;
+
+PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
+    list_files.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        list_files.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          list_files.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
+  VAR
+    temp:Tdata;
+  BEGIN
+    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
+    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
+  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);
+  END;
+
+PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
+  BEGIN
+    Form1.list_files.Height:=Form1.Splitter1.Top-23;
+    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-21;
+  END;
+
+PROCEDURE TForm1.menu_previewClick(Sender: TObject);
+  BEGIN
+    Form5.Visible:=NOT Form5.Visible;
+  END;
+
+PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
+  BEGIN
+    btn_extractcancel.Caption:='Cancel_';
+  END;
+
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+PROCEDURE TForm1.menu_txmpreplaceClick(Sender: TObject);
+  BEGIN
+    Form7.Visible:=NOT Form7.Visible;
+  END;
+
+PROCEDURE TForm1.menu_loaddatClick(Sender: TObject);
+  BEGIN
+    LoadDat;
+  END;
+
+PROCEDURE TForm1.menu_bineditClick(Sender: TObject);
+  BEGIN
+    Form8.Visible:=NOT Form8.Visible;
+  END;
+
+PROCEDURE TForm1.menu_extractfileClick(Sender: TObject);
+  VAR
+    result:Integer;
+    id:LongWord;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    result:=ExportFile(id,True);
+    CASE result OF
+      0{export_noerror}: BEGIN END;
+      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
+      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
+      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
+    ELSE
+      ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
+    END;
+    Form1.list_files.SetFocus;
+  END;
+
+PROCEDURE TForm1.menu_extractlistClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    group_progress.Visible:=True;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=120;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=list_files.Items.Count;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    errors:=0;
+    FOR i:=0 TO progress.Max-1 DO BEGIN
+      IF ExportFile(StrToInt(MidStr(list_files.Items.Strings[i],1,5)),True)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(progress.Max);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    group_progress.Visible:=False;
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+  END;
+
+PROCEDURE TForm1.menu_extractallClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    group_progress.Visible:=True;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=120;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=dat_header.files;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    errors:=0;
+    FOR i:=0 TO High(dat_files) DO BEGIN
+      IF ExportFile(i,True)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    group_progress.Visible:=False;
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+  END;
+
+END.
Index: /oup/releases/0.16a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.16a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.16a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,216 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, SQLiteTable3, Unit3_data, Unit4_Exporters;
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+
+FUNCTION LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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>=1024*1024*1024 THEN BEGIN
+      Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB';
+    END ELSE BEGIN
+      IF size>=1024*1024 THEN BEGIN
+        Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB';
+      END ELSE BEGIN
+        IF size>=1024 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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    //ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      //ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.16a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.16a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.16a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,84 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.16a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  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;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.16a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.16a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.16a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,181 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+    {
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+    }
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DAT_'),fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+    {
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.16a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.16a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.16a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,74 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 435
+  Height = 348
+  BorderStyle = bsSizeToolWin
+  Caption = 'Preview'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object img: TImage
+    Left = 0
+    Top = 20
+    Width = 427
+    Height = 304
+    Align = alClient
+  end
+  object panel_buttons: TPanel
+    Left = 0
+    Top = 0
+    Width = 427
+    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
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 72
+    Top = 48
+  end
+end
Index: /oup/releases/0.16a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.16a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.16a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,183 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    img: TImage;
+    timer: TTimer;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    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 FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE ShowPreview(fileid:LongWord);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  memstreams:Array OF TMemoryStream;
+  actualimg:Byte;
+  _fileid:LongWord;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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;
+    Form5.timer.Interval:=Floor(loop_speed*(1/60)*1000);
+    Form5.timer.Enabled:=False;
+    Form5.btn_startstopClick(Form5); 
+    Form5.panel_buttons.Visible:=True;
+  END;
+
+PROCEDURE TForm5.ShowPreview(fileid:LongWord);
+  BEGIN
+    _fileid:=fileid;
+    Form5.timer.Enabled:=False;
+    Form5.panel_buttons.Visible:=False;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[fileid].Extension='TXAN' THEN PreviewTXAN;
+    IF dat_files[fileid].Extension='TXMB' THEN PreviewTXMB;
+    IF dat_files[fileid].Extension='TXMP' THEN PreviewTXMP;
+  END;
+
+PROCEDURE TForm5.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form5.Visible:=False;
+  END;
+
+PROCEDURE TForm5.FormCreate(Sender: TObject);
+  BEGIN
+    SetLength(memstreams,1);
+    memstreams[0]:=TMemoryStream.Create;
+    Form5.Width:=260;
+    Form5.Height:=300;
+  END;
+
+PROCEDURE TForm5.timerTimer(Sender: TObject);
+  BEGIN
+    Inc(actualimg);
+    IF actualimg>=Length(memstreams) THEN actualimg:=0;
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+    Form5.Caption:='Preview '+dat_files[_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
+    Form5.timer.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_dec.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_inc.Enabled:=NOT Form5.timer.Enabled;
+    IF Form5.timer.Enabled THEN
+      Form5.btn_startstop.Caption:='Stop automatic'
+    ELSE
+      Form5.btn_startstop.Caption:='Start automatic';
+  END;
+
+PROCEDURE TForm5.FormResize(Sender: TObject);
+  BEGIN
+    IF Form5.Width>=150 THEN BEGIN
+    END ELSE Form5.Width:=150;
+    IF Form5.Height>=150 THEN BEGIN
+    END ELSE Form5.Height:=150;
+  END;
+
+PROCEDURE TForm5.btn_decClick(Sender: TObject);
+  BEGIN
+    IF actualimg>0 THEN
+      Dec(actualimg)
+    ELSE
+      actualimg:=High(memstreams);
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.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;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+END.
Index: /oup/releases/0.16a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.16a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.16a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,398 @@
+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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,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.16a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.16a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.16a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,161 @@
+object Form7: TForm7
+  Left = 0
+  Top = 0
+  Width = 400
+  Height = 453
+  BorderStyle = bsSizeToolWin
+  Caption = 'TXMP Replacer'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_12: TPanel
+    Left = 0
+    Top = 0
+    Width = 392
+    Height = 350
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter1: TSplitter
+      Left = 200
+      Top = 0
+      Width = 8
+      Height = 350
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object group_txmpselect: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 200
+      Height = 350
+      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 = 150
+        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
+    end
+    object group_bmpselect: TGroupBox
+      Left = 208
+      Top = 0
+      Width = 184
+      Height = 350
+      Align = alClient
+      Caption = '2. Open BMP to replace with'
+      Enabled = False
+      TabOrder = 1
+      object image_bmppreview: TImage
+        Left = 2
+        Top = 45
+        Width = 180
+        Height = 303
+        Align = alClient
+      end
+      object panel_load: TPanel
+        Left = 2
+        Top = 15
+        Width = 180
+        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 = 350
+    Width = 392
+    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
+end
Index: /oup/releases/0.16a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.16a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.16a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,217 @@
+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;
+    image_txmppreview: TImage;
+    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;
+    PROCEDURE btn_replaceClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+    PROCEDURE list_txmpClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE RecreateTXMPlist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit6_imgfuncs;
+{$R *.dfm}
+VAR
+  actual_bmpdata:Tdata;
+
+PROCEDURE TForm7.RecreateTXMPlist;
+  VAR
+    i:LongWord;
+  BEGIN
+    Form7.list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        Form7.list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    Form7.group_bmpselect.Enabled:=False;
+    Form7.check_transparency.Checked:=False;
+    Form7.check_fading.Checked:=False;
+  END;
+
+PROCEDURE TForm7.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form7.Visible:=False;
+  END;
+
+PROCEDURE TForm7.FormResize(Sender: TObject);
+  BEGIN
+    IF Form7.Width>=400 THEN BEGIN
+    END ELSE Form7.Width:=400;
+    IF Form7.Height>=350 THEN BEGIN
+    END ELSE Form7.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);
+    Form7.check_fading.Checked:=(fadingbyte AND $01)>0;
+    Form7.check_transparency.Checked:=(depthbyte AND $04)>0;
+    Form7.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);
+    Form7.image_txmppreview.Picture.Bitmap.LoadFromStream(mem);
+    mem.Free;
+
+    Form7.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);
+      Form7.image_bmppreview.Picture.Bitmap.LoadFromStream(mem);
+      mem.Free;
+
+      Form7.group_options.Enabled:=True;
+    END;
+  END;
+
+PROCEDURE TForm7.btn_replaceClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    imgpkg:TImgPackage;
+    rawfile:TFileStream;
+    datfile:TFileStream;
+    dataddr:LongWord;
+    old_rawaddr,new_rawaddr:LongWord;
+    oldwidth,oldheight:Word;
+    oldstore,olddepth,oldfading:Byte;
+    oldsize:LongWord;
+    newsize:LongWord;
+    datbyte:Word;
+  BEGIN
+    IF Form7.list_txmp.ItemIndex>=0 THEN BEGIN
+      imgpkg:=BmpToImgdata(actual_bmpdata,check_32bit.Checked);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Read(oldfading,1);
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Read(olddepth,1);
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Read(oldstore,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Read(old_rawaddr,4);
+      IF (oldwidth<>imgpkg.imgx) OR (oldheight<>imgpkg.imgy) THEN BEGIN
+        IF MessageBox(Form7.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,Form7.check_fading.Checked)
+      ELSE
+        newsize:=GetImageDataSize(imgpkg.imgx,imgpkg.imgy,16,Form7.check_fading.Checked);
+
+      IF newsize<=oldsize THEN
+        new_rawaddr:=old_rawaddr
+      ELSE
+        new_rawaddr:=rawfile.Size;
+
+      datbyte:=$00;
+      IF Form7.check_fading.Checked THEN datbyte:=datbyte OR $01;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datbyte:=$10;
+      IF Form7.check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      IF Form7.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;
+
+END.
Index: /oup/releases/0.16a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.16a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.16a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,74 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  AutoScroll = False
+  BorderStyle = bsSizeToolWin
+  Caption = 'Form8'
+  ClientHeight = 617
+  ClientWidth = 714
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 161
+    Top = 0
+    Width = 9
+    Height = 617
+    Beveled = True
+  end
+  object hex: TMPHexEditor
+    Left = 170
+    Top = 0
+    Width = 544
+    Height = 617
+    Cursor = crIBeam
+    Align = alClient
+    Font.Charset = DEFAULT_CHARSET
+    Font.Color = clWindowText
+    Font.Height = -16
+    Font.Name = 'Courier'
+    Font.Style = []
+    ParentFont = False
+    ScrollBars = ssVertical
+    TabOrder = 1
+    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
+    AllowInsertMode = False
+    DrawGridLines = False
+    Version = 'May 23, 2005; '#169' markus stephany, vcl[at]mirkes[dot]de'
+    ShowPositionIfNotFocused = True
+  end
+  object list: TListBox
+    Left = 0
+    Top = 0
+    Width = 161
+    Height = 617
+    Align = alLeft
+    ItemHeight = 13
+    TabOrder = 0
+    OnClick = listClick
+  end
+end
Index: /oup/releases/0.16a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.16a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.16a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,77 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, Unit3_data, Unit2_functions,
+  ExtCtrls;
+
+TYPE
+  TForm8 = Class(TForm)
+    list: TListBox;
+    hex: TMPHexEditor;
+    Splitter1: TSplitter;
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE Recreatelist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+VAR
+  fileid:LongWord;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+  BEGIN
+    Form8.list.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].FileType AND $02)=0 THEN
+        Form8.list.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm8.FormCreate(Sender: TObject);
+  BEGIN
+    Form8.Caption:='';
+    fileid:=0;
+  END;
+
+PROCEDURE TForm8.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form8.Visible:=False;
+  END;
+
+PROCEDURE TForm8.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF MessageBox(Form8.Handle,PChar('Save changes to file '+dat_files[fileid].FileName+'?'),PChar('Data changed...'),MB_YESNO)=IDYES THEN BEGIN
+        mem:=TMemoryStream.Create;
+        hex.SaveToStream(mem);
+        mem.Seek(0,soFromBeginning);
+        SetLength(data,mem.Size);
+        mem.Read(data[0],mem.Size); 
+        mem.Free;
+        SaveDatFile(fileid,data);
+        ShowMessage('Changes saved...');
+      END;
+    END;
+    fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
+    data:=LoadDatFile(fileid);
+    mem:=TMemoryStream.Create;
+    mem.Write(data[0],Length(data));
+    hex.LoadFromStream(mem);
+    mem.Free;
+  END;
+
+END.
Index: /oup/releases/0.17a/_changelog.txt
===================================================================
--- /oup/releases/0.17a/_changelog.txt	(revision 8)
+++ /oup/releases/0.17a/_changelog.txt	(revision 8)
@@ -0,0 +1,29 @@
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.17a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.17a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.17a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.17a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.17a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.17a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,15 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.17a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.17a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.17a/src/OniUnPacker.cfg	(revision 8)
@@ -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.17a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.17a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.17a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,23 @@
+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};
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm5, Form5);
+  Application.CreateForm(TForm7, Form7);
+  Application.CreateForm(TForm8, Form8);
+  Application.Run;
+END.
Index: /oup/releases/0.17a/src/SQLite3.pas
===================================================================
--- /oup/releases/0.17a/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.17a/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.17a/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.17a/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.17a/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,883 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.17a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.17a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.17a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,297 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 563
+  ClientWidth = 692
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  Menu = menu
+  OldCreateOrder = False
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_all: TPanel
+    Left = 0
+    Top = 100
+    Width = 692
+    Height = 300
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter2: TSplitter
+      Left = 360
+      Top = 0
+      Width = 8
+      Height = 300
+      AutoSnap = False
+      Beveled = True
+      MinSize = 360
+    end
+    object panel_left: TPanel
+      Left = 0
+      Top = 0
+      Width = 360
+      Height = 300
+      Cursor = crDrag
+      Align = alLeft
+      BevelOuter = bvNone
+      TabOrder = 0
+      object Splitter1: TSplitter
+        Left = 0
+        Top = 241
+        Width = 360
+        Height = 8
+        Cursor = crVSplit
+        Align = alTop
+        AutoSnap = False
+        Beveled = True
+        MinSize = 75
+        OnMoved = Splitter1Moved
+      end
+      object panel_files: TPanel
+        Left = 0
+        Top = 0
+        Width = 360
+        Height = 241
+        Align = alTop
+        BevelOuter = bvNone
+        TabOrder = 0
+        object btn_extractconvert: TButton
+          Left = 1
+          Top = 220
+          Width = 358
+          Height = 20
+          Caption = 'Convert and extract file'
+          Enabled = False
+          TabOrder = 0
+          WordWrap = True
+          OnClick = btn_extractconvertClick
+        end
+        object list_files: TListBox
+          Left = 0
+          Top = 0
+          Width = 360
+          Height = 218
+          Align = alTop
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Fixedsys'
+          Font.Style = []
+          ItemHeight = 15
+          ParentFont = False
+          TabOrder = 1
+          OnClick = list_filesDblClick
+          OnDblClick = list_filesDblClick
+        end
+      end
+      object list_extensions: TListBox
+        Left = 0
+        Top = 249
+        Width = 360
+        Height = 51
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ItemHeight = 15
+        ParentFont = False
+        Sorted = True
+        TabOrder = 1
+        OnClick = list_extensionsClick
+        OnDblClick = list_extensionsClick
+      end
+    end
+    object panel_file: TPanel
+      Left = 368
+      Top = 0
+      Width = 324
+      Height = 300
+      Align = alClient
+      BevelOuter = bvNone
+      TabOrder = 1
+      object lbl_fileinfo: TLabel
+        Left = 0
+        Top = 0
+        Width = 324
+        Height = 44
+        Align = alTop
+        AutoSize = False
+      end
+      object lbl_zerobyte: TLabel
+        Left = 32
+        Top = 136
+        Width = 265
+        Height = 41
+        AutoSize = False
+        Caption = 
+          'Zero byte file. Oni will take the data for this file of level0_f' +
+          'inal.dat/raw'
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -16
+        Font.Name = 'Tahoma'
+        Font.Style = []
+        ParentFont = False
+        Visible = False
+        WordWrap = True
+      end
+      object hex: TMPHexEditor
+        Left = 0
+        Top = 44
+        Width = 324
+        Height = 256
+        Cursor = crIBeam
+        Align = alClient
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -16
+        Font.Name = 'Fixedsys'
+        Font.Style = []
+        ParentFont = False
+        TabOrder = 0
+        BytesPerRow = 16
+        Translation = tkAsIs
+        OffsetFormat = '6!10:0x|'
+        Colors.Background = clWindow
+        Colors.ChangedBackground = clWhite
+        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 = False
+        AllowInsertMode = False
+        DrawGridLines = False
+        ReadOnlyView = True
+        Version = 'May 23, 2005; '#169' markus stephany, vcl[at]mirkes[dot]de'
+      end
+    end
+  end
+  object group_progress: TGroupBox
+    Left = 296
+    Top = 480
+    Width = 297
+    Height = 57
+    Caption = 'Extracting...'
+    TabOrder = 1
+    Visible = False
+    object lbl_progress: TLabel
+      Left = 10
+      Top = 36
+      Width = 279
+      Height = 18
+      AutoSize = False
+    end
+    object progress: TProgressBar
+      Left = 8
+      Top = 16
+      Width = 217
+      Height = 17
+      Step = 1
+      TabOrder = 0
+    end
+    object btn_extractcancel: TButton
+      Left = 232
+      Top = 16
+      Width = 57
+      Height = 33
+      Caption = 'Cancel'
+      TabOrder = 1
+      OnClick = btn_extractcancelClick
+    end
+  end
+  object statbar: TStatusBar
+    Left = 0
+    Top = 546
+    Width = 692
+    Height = 17
+    BiDiMode = bdLeftToRight
+    Panels = <
+      item
+        Text = 'Current .dat: -'
+        Width = 500
+      end
+      item
+        Text = 'Files: -'
+        Width = 90
+      end
+      item
+        Text = 'Extensions: -'
+        Width = 100
+      end>
+    ParentBiDiMode = False
+  end
+  object fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    Left = 64
+    Top = 120
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 224
+    object menu_main: TMenuItem
+      Caption = '&Main'
+      object menu_loaddat: TMenuItem
+        Caption = '&Select .dat-file ...'
+        OnClick = menu_loaddatClick
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_extract: TMenuItem
+      Caption = '&Extract/Convert'
+      Enabled = False
+      object menu_extractfile: TMenuItem
+        Caption = 'Convert and extract current &file'
+        OnClick = menu_extractfileClick
+      end
+      object menu_extractlist: TMenuItem
+        Caption = 'Convert and extract all files currently in &list'
+        OnClick = menu_extractlistClick
+      end
+      object menu_extractall: TMenuItem
+        Caption = 'Convert and extract &all files'
+        OnClick = menu_extractallClick
+      end
+    end
+    object menu_tools: TMenuItem
+      Caption = '&Tools'
+      Enabled = False
+      object menu_preview: TMenuItem
+        Caption = '&Preview Window ...'
+        OnClick = menu_previewClick
+      end
+      object menu_binedit: TMenuItem
+        Caption = '&Binary .dat editor ...'
+        OnClick = menu_bineditClick
+      end
+      object menu_txmpreplace: TMenuItem
+        Caption = '&TXMP replacer ...'
+        OnClick = menu_txmpreplaceClick
+      end
+    end
+  end
+end
Index: /oup/releases/0.17a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.17a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,439 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace, Unit8_binedit,
+  Grids, MPHexEditor;
+
+TYPE
+  TForm1 = Class(TForm)
+    panel_all: TPanel;
+    panel_left: TPanel;
+    Splitter1: TSplitter;
+    panel_files: TPanel;
+    btn_extractconvert: TButton;
+    list_files: TListBox;
+    list_extensions: TListBox;
+    Splitter2: TSplitter;
+    fopen: TOpenDialog;
+    group_progress: TGroupBox;
+    progress: TProgressBar;
+    lbl_progress: TLabel;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    btn_extractcancel: TButton;
+    menu_tools: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    menu_extract: TMenuItem;
+    menu_extractfile: TMenuItem;
+    menu_extractlist: TMenuItem;
+    menu_extractall: TMenuItem;
+    menu_loaddat: TMenuItem;
+    menu_sep1: TMenuItem;
+    menu_binedit: TMenuItem;
+    statbar: TStatusBar;
+    panel_file: TPanel;
+    lbl_fileinfo: TLabel;
+    hex: TMPHexEditor;
+    lbl_zerobyte: TLabel;
+    PROCEDURE menu_extractallClick(Sender: TObject);
+    PROCEDURE menu_extractlistClick(Sender: TObject);
+    PROCEDURE menu_extractfileClick(Sender: TObject);
+    PROCEDURE menu_bineditClick(Sender: TObject);
+    PROCEDURE menu_loaddatClick(Sender: TObject);
+    PROCEDURE menu_txmpreplaceClick(Sender: TObject);
+    PROCEDURE menu_exitClick(Sender: TObject);
+    PROCEDURE btn_extractcancelClick(Sender: TObject);
+    PROCEDURE menu_previewClick(Sender: TObject);
+    PROCEDURE Splitter1Moved(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE btn_hexcopyClick(Sender: TObject);
+    PROCEDURE list_extensionsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE btn_extractconvertClick(Sender: TObject);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE list_filesDblClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form1: TForm1;
+
+IMPLEMENTATION
+{$R *.dfm}
+
+PROCEDURE DoAfterLoadOfADat;
+  VAR
+    i:LongWord;
+    txt:Text;
+    temp4:LongWord;
+    temp2:Word;
+    temp1:Byte;
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXMP-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='M') AND
+          (dat_extensionsmap[i].Extension[0]='P') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXMP-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'MipMap'+#9+'Depth'+#9+'ImgX'+#9+'ImgY'+#9+'StoreT');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXMP' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$88,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$89,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        LoadDatFilePart(i,$8C,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$8E,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$90,1,@temp1);
+        Write(txt,IntToHex(temp1,2)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    AssignFile(txt,GetExtractPath+'\___TXAN-FILES___.TXT');
+    ReWrite(txt);
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      IF (dat_extensionsmap[i].Extension[3]='T') AND
+          (dat_extensionsmap[i].Extension[2]='X') AND
+          (dat_extensionsmap[i].Extension[1]='A') AND
+          (dat_extensionsmap[i].Extension[0]='N') THEN BEGIN
+        WriteLn(txt, FormatNumber(dat_extensionsmap[i].ExtCount,4,'0')+' TXAN-Files');
+        Break;
+      END;
+    END;
+    WriteLn(txt,'FileName'+#9+'Loopspeed'+#9+'Unknown'+#9+'Links');
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF dat_files[i].Extension='TXAN' THEN BEGIN
+        Write(txt,dat_files[i].FileName+#9);
+        LoadDatFilePart(i,$14,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$16,2,@temp2);
+        Write(txt,IntToHex(temp2,4)+#9);
+        LoadDatFilePart(i,$1C,4,@temp4);
+        Write(txt,IntToHex(temp4,8)+#9);
+        WriteLn(txt,'');
+      END;
+    END;
+    CloseFile(txt);
+  END;
+
+PROCEDURE LoadDat;
+  VAR i:LongWord;
+  BEGIN
+    Form1.fopen.InitialDir:=AppSettings.DatPath;
+    IF Form1.fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(Form1.fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(Form1.fopen.FileName);
+      Form1.list_files.Items.Clear;
+      Form1.list_extensions.Items.Clear;
+      IF LoadDatInfos(Form1.fopen.FileName) THEN BEGIN
+        Form1.list_extensions.Items.Add('_All files: '+FormatNumber(dat_header.Files,4,' '));
+        FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+          WITH dat_extensionsmap[i] DO BEGIN
+            Form1.list_extensions.Items.Add(
+                Extension[3]+Extension[2]+Extension[1]+Extension[0]+': '+
+                FormatNumber(ExtCount,4,' '));{+' (Ident: 0x'+
+                IntToHex(Ident[7],2)+IntToHex(Ident[6],2)+IntToHex(Ident[5],2)+IntToHex(Ident[4],2)+IntToHex(Ident[3],2)+IntToHex(Ident[2],2)+IntToHex(Ident[1],2)+IntToHex(Ident[0],2)+')');}
+          END;
+        END;
+        Form1.list_extensions.ItemIndex:=0;
+        Form1.list_extensionsClick(Form1);
+        Form1.list_files.ItemIndex:=0;
+        Form1.list_filesDblClick(Form1);
+        Form1.statbar.Panels.Items[0].Text:='Current .dat: '+dat_FileName;
+        Form1.statbar.Panels.Items[1].Text:='Files: '+IntToStr(dat_header.Files);
+        Form1.statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(dat_header.Extensions);
+        Form1.menu_tools.Enabled:=True;
+        Form1.menu_extract.Enabled:=True;
+        Form1.btn_extractconvert.Enabled:=True;
+
+        Form7.RecreateTXMPlist;
+        Form8.Recreatelist;
+
+        DoAfterLoadOfADat;
+
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+Form1.fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+PROCEDURE TForm1.btn_loadClick(Sender: TObject);
+  BEGIN
+    LoadDat;
+  END;
+
+PROCEDURE TForm1.list_filesDblClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    temp:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    IF (dat_files[id].FileType AND $02)=0 THEN BEGIN
+      lbl_fileinfo.Caption:=
+            'Filename: '+dat_files[id].FileName+CrLf+
+            'Size: '+FormatFileSize(dat_files[id].Size)+' ('+IntToStr(dat_files[id].Size)+' Bytes)'+CrLf+
+            'Address in .dat: 0x'+IntTohex(dat_files[id].DatAddr,8);
+      temp:=LoadDatFile(id);
+      mem:=TMemoryStream.Create;
+      mem.Write(temp[0],Length(temp));
+      hex.LoadFromStream(mem);
+      mem.Free;
+      Form5.ShowPreview(id);
+      lbl_zerobyte.Visible:=False;
+      hex.Visible:=True;
+    END ELSE BEGIN
+      lbl_fileinfo.Caption:=
+            'Filename: '+dat_files[id].FileName;
+      lbl_zerobyte.Visible:=True;
+      hex.Visible:=False;
+    END;
+  END;
+
+PROCEDURE TForm1.FormCreate(Sender: TObject);
+  BEGIN
+    Form1.Caption:='Oni Un/Packer '+version;
+    Form1.FormResize(Form1);
+
+    panel_all.Align:=alClient;
+
+    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.btn_extractconvertClick(Sender: TObject);
+  BEGIN
+    Form1.menu_extractfileClick(Form1);
+  END;
+
+PROCEDURE TForm1.FormResize(Sender: TObject);
+  CONST
+    MinWidth:Integer=750;
+    MinHeight:Integer=500;
+  BEGIN
+    IF NOT group_progress.Visible THEN 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 ELSE BEGIN
+      Form1.Width:=400;
+      Form1.Height:=120;
+    END;
+  END;
+
+PROCEDURE TForm1.list_extensionsClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(list_extensions.Items.Strings[list_extensions.ItemIndex],1,4);
+    list_files.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        list_files.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          list_files.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm1.btn_hexcopyClick(Sender: TObject);
+  VAR
+    temp:Tdata;
+  BEGIN
+    temp:=LoadDatFile(StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5)));
+    Clipboard.SetTextBuf(PChar(CreateHexString(temp,True)));
+  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);
+  END;
+
+PROCEDURE TForm1.Splitter1Moved(Sender: TObject);
+  BEGIN
+    Form1.list_files.Height:=Form1.Splitter1.Top-23;
+    Form1.btn_extractconvert.Top:=Form1.Splitter1.Top-21;
+  END;
+
+PROCEDURE TForm1.menu_previewClick(Sender: TObject);
+  BEGIN
+    Form5.Visible:=NOT Form5.Visible;
+  END;
+
+PROCEDURE TForm1.btn_extractcancelClick(Sender: TObject);
+  BEGIN
+    btn_extractcancel.Caption:='Cancel_';
+  END;
+
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+PROCEDURE TForm1.menu_txmpreplaceClick(Sender: TObject);
+  BEGIN
+    Form7.Visible:=NOT Form7.Visible;
+  END;
+
+PROCEDURE TForm1.menu_loaddatClick(Sender: TObject);
+  BEGIN
+    LoadDat;
+  END;
+
+PROCEDURE TForm1.menu_bineditClick(Sender: TObject);
+  BEGIN
+    Form8.Visible:=NOT Form8.Visible;
+  END;
+
+PROCEDURE TForm1.menu_extractfileClick(Sender: TObject);
+  VAR
+    result:Integer;
+    id:LongWord;
+  BEGIN
+    id:=StrToInt(MidStr(list_files.Items.Strings[list_files.ItemIndex],1,5));
+    result:=ExportFile(id,True);
+    CASE result OF
+      0{export_noerror}: BEGIN END;
+      1{export_nohandler}: ShowMessage('No export-handler for files with extension '+dat_files[id].Extension+'.');
+      2{export_handlererror}: ShowMessage('Error while running data-handler for '+CrLf+dat_files[id].FileName);
+      3{export_error}: ShowMessage('Error while exporting file '+CrLf+dat_files[id].FileName);
+    ELSE
+      ShowMessage('Couldn''t export file '+FormatNumber(id,5,'0')+CrLf+'(Unknown error)');
+    END;
+    Form1.list_files.SetFocus;
+  END;
+
+PROCEDURE TForm1.menu_extractlistClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    group_progress.Visible:=True;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=120;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=list_files.Items.Count;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    errors:=0;
+    FOR i:=0 TO progress.Max-1 DO BEGIN
+      IF ExportFile(StrToInt(MidStr(list_files.Items.Strings[i],1,5)),True)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(progress.Max);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    group_progress.Visible:=False;
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+  END;
+
+PROCEDURE TForm1.menu_extractallClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    errors:LongWord;
+    oldwidth,oldheight:Integer;
+    oldstate:TWindowState;
+  BEGIN
+    panel_all.Visible:=False;
+    group_progress.Visible:=True;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=False;
+    oldwidth:=Form1.Width;
+    oldheight:=Form1.Height;
+    oldstate:=Form1.WindowState;
+    Form1.WindowState:=wsNormal;
+    Form1.Width:=400;
+    Form1.Height:=120;
+    group_progress.Left:=0;
+    group_progress.Top:=0;
+    group_progress.Width:=Form1.Width-8;
+    progress.Width:=group_progress.Width-80;
+    progress.Max:=dat_header.files;
+    btn_extractcancel.Left:=group_progress.Width-65;
+    btn_extractcancel.Caption:='Cancel';
+    btn_extractcancel.SetFocus;
+
+    errors:=0;
+    FOR i:=0 TO High(dat_files) DO BEGIN
+      IF ExportFile(i,True)>0 THEN Inc(errors);
+      IF (i MOD 25)=0 THEN BEGIN
+        lbl_progress.Caption:=IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        progress.Position:=i;
+        Application.ProcessMessages;
+        IF btn_extractcancel.Caption='Cancel_' THEN BEGIN
+          btn_extractcancel.Caption:='Cancel';
+          Break;
+        END;
+      END;
+    END;
+    IF errors>0 THEN
+      ShowMessage(IntToStr(errors)+' errors encountered.');
+
+    group_progress.Visible:=False;
+    Form1.Width:=oldwidth;
+    Form1.Height:=oldheight;
+    Form1.WindowState:=oldstate;
+    //FOR i:=0 TO menu.ComponentCount DO menu.Items.Items[i].Enabled:=True;
+    panel_all.Visible:=True;
+  END;
+
+END.
Index: /oup/releases/0.17a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.17a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,255 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, SQLiteTable3, Unit3_data, Unit4_Exporters;
+
+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 LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+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
+    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 LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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>=1024*1024*1024 THEN BEGIN
+      Result:=FloatToStrF(size/1024/1024/1024,ffFixed,5,1)+' GB';
+    END ELSE BEGIN
+      IF size>=1024*1024 THEN BEGIN
+        Result:=FloatToStrF(size/1024/1024,ffFixed,5,1)+' MB';
+      END ELSE BEGIN
+        IF size>=1024 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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    //ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      //ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.17a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.17a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,84 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.17a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  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;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.17a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.17a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,181 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+    {
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+    }
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DAT_'),fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+    {
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.17a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.17a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.17a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,74 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 435
+  Height = 348
+  BorderStyle = bsSizeToolWin
+  Caption = 'Preview'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsStayOnTop
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object img: TImage
+    Left = 0
+    Top = 20
+    Width = 427
+    Height = 304
+    Align = alClient
+  end
+  object panel_buttons: TPanel
+    Left = 0
+    Top = 0
+    Width = 427
+    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
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 72
+    Top = 48
+  end
+end
Index: /oup/releases/0.17a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.17a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,183 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    img: TImage;
+    timer: TTimer;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    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 FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE ShowPreview(fileid:LongWord);
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  memstreams:Array OF TMemoryStream;
+  actualimg:Byte;
+  _fileid:LongWord;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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);
+
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[0]);
+  END;
+
+PROCEDURE 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;
+    Form5.timer.Interval:=Floor(loop_speed*(1/60)*1000);
+    Form5.timer.Enabled:=False;
+    Form5.btn_startstopClick(Form5); 
+    Form5.panel_buttons.Visible:=True;
+  END;
+
+PROCEDURE TForm5.ShowPreview(fileid:LongWord);
+  BEGIN
+    _fileid:=fileid;
+    Form5.timer.Enabled:=False;
+    Form5.panel_buttons.Visible:=False;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[fileid].Extension='TXAN' THEN PreviewTXAN;
+    IF dat_files[fileid].Extension='TXMB' THEN PreviewTXMB;
+    IF dat_files[fileid].Extension='TXMP' THEN PreviewTXMP;
+  END;
+
+PROCEDURE TForm5.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form5.Visible:=False;
+  END;
+
+PROCEDURE TForm5.FormCreate(Sender: TObject);
+  BEGIN
+    SetLength(memstreams,1);
+    memstreams[0]:=TMemoryStream.Create;
+    Form5.Width:=260;
+    Form5.Height:=300;
+  END;
+
+PROCEDURE TForm5.timerTimer(Sender: TObject);
+  BEGIN
+    Inc(actualimg);
+    IF actualimg>=Length(memstreams) THEN actualimg:=0;
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+    Form5.Caption:='Preview '+dat_files[_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
+    Form5.timer.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_dec.Enabled:=NOT Form5.timer.Enabled;
+    Form5.btn_inc.Enabled:=NOT Form5.timer.Enabled;
+    IF Form5.timer.Enabled THEN
+      Form5.btn_startstop.Caption:='Stop automatic'
+    ELSE
+      Form5.btn_startstop.Caption:='Start automatic';
+  END;
+
+PROCEDURE TForm5.FormResize(Sender: TObject);
+  BEGIN
+    IF Form5.Width>=150 THEN BEGIN
+    END ELSE Form5.Width:=150;
+    IF Form5.Height>=150 THEN BEGIN
+    END ELSE Form5.Height:=150;
+  END;
+
+PROCEDURE TForm5.btn_decClick(Sender: TObject);
+  BEGIN
+    IF actualimg>0 THEN
+      Dec(actualimg)
+    ELSE
+      actualimg:=High(memstreams);
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.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;
+    Form5.Caption:='Preview '+dat_files[_fileid].FileName+' ('+IntToStr(actualimg+1)+'/'+IntToStr(Length(memstreams))+')';
+    Form5.img.Picture.Bitmap.LoadFromStream(memstreams[actualimg]);
+    memstreams[actualimg].Seek(0,soFromBeginning);
+  END;
+
+END.
Index: /oup/releases/0.17a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.17a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,398 @@
+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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,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.17a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.17a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.17a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,161 @@
+object Form7: TForm7
+  Left = 0
+  Top = 0
+  Width = 400
+  Height = 453
+  BorderStyle = bsSizeToolWin
+  Caption = 'TXMP Replacer'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object panel_12: TPanel
+    Left = 0
+    Top = 0
+    Width = 392
+    Height = 350
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object Splitter1: TSplitter
+      Left = 200
+      Top = 0
+      Width = 8
+      Height = 350
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object group_txmpselect: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 200
+      Height = 350
+      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 = 150
+        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
+    end
+    object group_bmpselect: TGroupBox
+      Left = 208
+      Top = 0
+      Width = 184
+      Height = 350
+      Align = alClient
+      Caption = '2. Open BMP to replace with'
+      Enabled = False
+      TabOrder = 1
+      object image_bmppreview: TImage
+        Left = 2
+        Top = 45
+        Width = 180
+        Height = 303
+        Align = alClient
+      end
+      object panel_load: TPanel
+        Left = 2
+        Top = 15
+        Width = 180
+        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 = 350
+    Width = 392
+    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
+end
Index: /oup/releases/0.17a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.17a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,217 @@
+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;
+    image_txmppreview: TImage;
+    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;
+    PROCEDURE btn_replaceClick(Sender: TObject);
+    PROCEDURE btn_loadClick(Sender: TObject);
+    PROCEDURE list_txmpClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE RecreateTXMPlist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit6_imgfuncs;
+{$R *.dfm}
+VAR
+  actual_bmpdata:Tdata;
+
+PROCEDURE TForm7.RecreateTXMPlist;
+  VAR
+    i:LongWord;
+  BEGIN
+    Form7.list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        Form7.list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    Form7.group_bmpselect.Enabled:=False;
+    Form7.check_transparency.Checked:=False;
+    Form7.check_fading.Checked:=False;
+  END;
+
+PROCEDURE TForm7.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form7.Visible:=False;
+  END;
+
+PROCEDURE TForm7.FormResize(Sender: TObject);
+  BEGIN
+    IF Form7.Width>=400 THEN BEGIN
+    END ELSE Form7.Width:=400;
+    IF Form7.Height>=350 THEN BEGIN
+    END ELSE Form7.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);
+    Form7.check_fading.Checked:=(fadingbyte AND $01)>0;
+    Form7.check_transparency.Checked:=(depthbyte AND $04)>0;
+    Form7.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);
+    Form7.image_txmppreview.Picture.Bitmap.LoadFromStream(mem);
+    mem.Free;
+
+    Form7.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);
+      Form7.image_bmppreview.Picture.Bitmap.LoadFromStream(mem);
+      mem.Free;
+
+      Form7.group_options.Enabled:=True;
+    END;
+  END;
+
+PROCEDURE TForm7.btn_replaceClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    imgpkg:TImgPackage;
+    rawfile:TFileStream;
+    datfile:TFileStream;
+    dataddr:LongWord;
+    old_rawaddr,new_rawaddr:LongWord;
+    oldwidth,oldheight:Word;
+    oldstore,olddepth,oldfading:Byte;
+    oldsize:LongWord;
+    newsize:LongWord;
+    datbyte:Word;
+  BEGIN
+    IF Form7.list_txmp.ItemIndex>=0 THEN BEGIN
+      imgpkg:=BmpToImgdata(actual_bmpdata,check_32bit.Checked);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Read(oldfading,1);
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Read(olddepth,1);
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Read(oldstore,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Read(old_rawaddr,4);
+      IF (oldwidth<>imgpkg.imgx) OR (oldheight<>imgpkg.imgy) THEN BEGIN
+        IF MessageBox(Form7.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,Form7.check_fading.Checked)
+      ELSE
+        newsize:=GetImageDataSize(imgpkg.imgx,imgpkg.imgy,16,Form7.check_fading.Checked);
+
+      IF newsize<=oldsize THEN
+        new_rawaddr:=old_rawaddr
+      ELSE
+        new_rawaddr:=rawfile.Size;
+
+      datbyte:=$00;
+      IF Form7.check_fading.Checked THEN datbyte:=datbyte OR $01;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datbyte:=$10;
+      IF Form7.check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      IF Form7.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;
+
+END.
Index: /oup/releases/0.17a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.17a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.17a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,113 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  AutoScroll = False
+  BorderStyle = bsSizeToolWin
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 426
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 161
+    Top = 0
+    Width = 9
+    Height = 426
+    AutoSnap = False
+    Beveled = True
+    MinSize = 100
+  end
+  object list: TListBox
+    Left = 0
+    Top = 0
+    Width = 161
+    Height = 426
+    Align = alLeft
+    ItemHeight = 13
+    TabOrder = 0
+    OnClick = listClick
+  end
+  object panel_data: TPanel
+    Left = 170
+    Top = 0
+    Width = 472
+    Height = 426
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 1
+    OnResize = panel_dataResize
+    object Splitter2: TSplitter
+      Left = 0
+      Top = 300
+      Width = 472
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 100
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 472
+      Height = 300
+      Cursor = crIBeam
+      Align = alTop
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -16
+      Font.Name = 'Courier'
+      Font.Style = []
+      ParentFont = False
+      ScrollBars = ssVertical
+      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
+      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 = 309
+      Width = 472
+      Height = 117
+      Align = alClient
+      DefaultColWidth = 92
+      DefaultRowHeight = 18
+      FixedCols = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine]
+      TabOrder = 1
+      OnClick = structsClick
+    end
+  end
+end
Index: /oup/releases/0.17a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.17a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,235 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls,
+  Unit3_data, Unit2_functions, Unit9_data_structures;
+
+TYPE
+  TForm8 = Class(TForm)
+    list: TListBox;
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    PROCEDURE hexSelectionChanged(Sender: TObject);
+    PROCEDURE hexChange(Sender: TObject);
+    PROCEDURE panel_dataResize(Sender: TObject);
+    PROCEDURE structsClick(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE ClearStructViewer;
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE Recreatelist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+VAR
+  fileid:LongWord;
+
+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 GetTypeDataLength(datatype:Byte):Byte;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11..255: Result:=datatype-10;
+    END;
+  END;
+
+FUNCTION GetValue(datatype:Byte; offset:LongWord):String;
+  VAR
+    data:Tdata;
+  BEGIN
+    CASE datatype OF
+      1: Result:=IntToStr(Form8.hex.data[offset]);
+      2: Result:=IntToStr(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256);
+      3: Result:=IntToStr(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256+Form8.hex.data[offset+2]*256*256);
+      4: Result:=IntToStr(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256+Form8.hex.data[offset+2]*256*256+Form8.hex.data[offset+3]*256*256*256);
+      5: Result:='0x'+IntToHex(Form8.hex.data[offset],2);
+      6: Result:='0x'+IntToHex(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256,4);
+      7: Result:='0x'+IntToHex(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256+Form8.hex.data[offset+2]*256*256,6);
+      8: Result:='0x'+IntToHex(Form8.hex.data[offset]+Form8.hex.data[offset+1]*256+Form8.hex.data[offset+2]*256*256+Form8.hex.data[offset+3]*256*256*256,8);
+      9: BEGIN
+          SetLength(data,4);
+          data[0]:=Form8.hex.data[offset];
+          data[1]:=Form8.hex.data[offset+1];
+          data[2]:=Form8.hex.data[offset+2];
+          data[3]:=Form8.hex.data[offset+3];
+          Result:=FloatToStr(Decode_Float(data));
+        END;
+      10: Result:=IntToBin(Form8.hex.data[offset]);
+    END;
+  END;
+
+PROCEDURE WriteStructureInfos(structinfoid:Integer);
+  VAR
+    i:Byte;
+  BEGIN
+    IF structinfoid>=0 THEN BEGIN
+      WITH structure_infos[structinfoid] DO BEGIN
+        Form8.structs.RowCount:=Length(entries)+1;
+        FOR i:=1 TO Length(entries) DO BEGIN
+          Form8.structs.Cells[0,i]:=entries[i-1].name;
+          Form8.structs.Cells[1,i]:='0x'+IntToHex(entries[i-1].offset,6);
+          Form8.structs.Cells[2,i]:=GetDataType(entries[i-1].datatype);
+          Form8.structs.Cells[3,i]:=GetValue(entries[i-1].datatype,entries[i-1].offset);
+          Form8.structs.Cells[4,i]:=entries[i-1].description;
+        END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+  BEGIN
+    Form8.list.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].FileType AND $02)=0 THEN
+        Form8.list.Items.Add(dat_files[i].FileName);
+    END;
+  END;
+
+PROCEDURE TForm8.FormCreate(Sender: TObject);
+  BEGIN
+    Form8.Caption:='';
+    fileid:=0;
+    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;
+    Form8.panel_dataResize(Form8);
+  END;
+
+PROCEDURE TForm8.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    CanClose:=False;
+    Form8.Visible:=False;
+  END;
+
+PROCEDURE TForm8.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF MessageBox(Form8.Handle,PChar('Save changes to file '+dat_files[fileid].FileName+'?'),PChar('Data changed...'),MB_YESNO)=IDYES THEN BEGIN
+        mem:=TMemoryStream.Create;
+        hex.SaveToStream(mem);
+        mem.Seek(0,soFromBeginning);
+        SetLength(data,mem.Size);
+        mem.Read(data[0],mem.Size); 
+        mem.Free;
+        SaveDatFile(fileid,data);
+        ShowMessage('Changes saved...');
+      END;
+    END;
+    Form8.ClearStructViewer;
+    fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
+    data:=LoadDatFile(fileid);
+    mem:=TMemoryStream.Create;
+    mem.Write(data[0],Length(data));
+    hex.LoadFromStream(mem);
+    mem.Free;
+    WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  END;
+
+PROCEDURE TForm8.ClearStructViewer;
+  VAR
+    x:Word;
+  BEGIN
+    structs.RowCount:=2;
+    FOR x:=0 TO structs.ColCount-1 DO structs.Cells[x,1]:='';
+  END;
+
+PROCEDURE TForm8.FormResize(Sender: TObject);
+  BEGIN
+    IF Form8.Width>=650 THEN BEGIN
+    END ELSE Form8.Width:=650;
+    IF Form8.Height>=450 THEN BEGIN
+    END ELSE Form8.Height:=450;
+  END;
+
+PROCEDURE TForm8.structsClick(Sender: TObject);
+  VAR
+    offset:LongWord;
+    length:Byte;
+  BEGIN
+    IF structs.Row>0 THEN BEGIN
+      offset:=structure_infos[GetStructureInfoId(dat_files[fileid].extension)].entries[structs.Row-1].offset;
+      length:=GetTypeDataLength(structure_infos[GetStructureInfoId(dat_files[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]-12;
+  END;
+
+PROCEDURE TForm8.hexChange(Sender: TObject);
+  BEGIN
+    IF hex.DataSize>0 THEN
+      WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  END;
+
+PROCEDURE TForm8.hexSelectionChanged(Sender: TObject);
+  VAR
+    selstart,sellength,selend: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;
+      selend:=hex.SelEnd;
+      sellength:=hex.SelCount;
+      IF GetStructureInfoId(dat_files[fileid].Extension)>=0 THEN BEGIN
+        WITH structure_infos[GetStructureInfoId(dat_files[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;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.17a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.17a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.17a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,91 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils;
+
+TYPE
+  Tstructure_entry=RECORD
+      name:String;
+      offset:LongWord;
+      datatype:Byte;  // 1..4: Integer[1..4] dec; 5..8: Integer[1..4] hex; 9: float; 10: bitset; 11+: string[1+]
+      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:Byte):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+
+
+
+IMPLEMENTATION
+
+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:Byte):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';
+      11..255: Result:='String('+IntToStr(typeid-10)+')';
+    END;
+  END;
+
+PROCEDURE AddEntry(_ext:String; _name:String; _offset:LongWord; _datatype:Byte; _description:String);
+  VAR
+    sid:Word;
+  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:='TXMP';
+        typedesc:='Texture';
+      END;
+    END;
+  END;
+
+BEGIN
+  AddExtension('TXMP','Texture');
+  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','Raw-Link',$9C,8,'Address of the image data in the .raw-file');
+END.
Index: /oup/releases/0.18a/_changelog.txt
===================================================================
--- /oup/releases/0.18a/_changelog.txt	(revision 8)
+++ /oup/releases/0.18a/_changelog.txt	(revision 8)
@@ -0,0 +1,33 @@
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.18a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.18a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.18a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.18a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.18a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.18a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,16 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.18a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.18a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.18a/src/OniUnPacker.cfg	(revision 8)
@@ -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.18a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.18a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.18a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,21 @@
+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';
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.Run;
+END.
Index: /oup/releases/0.18a/src/SQLite3.pas
===================================================================
--- /oup/releases/0.18a/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.18a/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.18a/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.18a/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.18a/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,883 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.18a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.18a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.18a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,132 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 544
+  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
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object statbar: TStatusBar
+    Left = 0
+    Top = 527
+    Width = 692
+    Height = 17
+    BiDiMode = bdLeftToRight
+    Panels = <
+      item
+        Text = 'Current .dat: -'
+        Width = 500
+      end
+      item
+        Text = 'Files: -'
+        Width = 90
+      end
+      item
+        Text = 'Extensions: -'
+        Width = 100
+      end>
+    ParentBiDiMode = False
+  end
+  object fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    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_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_extract: TMenuItem
+      Caption = '&Extract/Convert'
+      Enabled = False
+      Visible = False
+      object menu_extractfile: TMenuItem
+        Caption = 'Convert and extract current &file'
+      end
+      object menu_extractlist: TMenuItem
+        Caption = 'Convert and extract all files currently in &list'
+      end
+      object menu_extractall: TMenuItem
+        Caption = 'Convert and extract &all files'
+      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
+    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
+end
Index: /oup/releases/0.18a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.18a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,299 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace, Unit8_binedit,
+  Grids, MPHexEditor, ToolWin, ImgList, Tabs;
+
+TYPE
+  TForm1 = Class(TForm)
+    fopen: TOpenDialog;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    menu_tools: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    menu_extract: TMenuItem;
+    menu_extractfile: TMenuItem;
+    menu_extractlist: TMenuItem;
+    menu_extractall: TMenuItem;
+    menu_loaddat: TMenuItem;
+    menu_sep1: TMenuItem;
+    menu_binedit: TMenuItem;
+    statbar: TStatusBar;
+    menu_windows: TMenuItem;
+    menu_windows_cascade: TMenuItem;
+    menu_windows_closeall: TMenuItem;
+    menu_sep2: TMenuItem;
+    menu_windows_tile: TMenuItem;
+    menu_sep3: TMenuItem;
+    menu_windows_next: TMenuItem;
+    menu_windows_previous: TMenuItem;
+    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}
+
+PROCEDURE LoadDat;
+  VAR i:LongWord;
+  BEGIN
+    Form1.fopen.InitialDir:=AppSettings.DatPath;
+    IF Form1.fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(Form1.fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(Form1.fopen.FileName);
+      IF LoadDatInfos(Form1.fopen.FileName) THEN BEGIN
+        Form1.statbar.Panels.Items[0].Text:='Current .dat: '+dat_FileName;
+        Form1.statbar.Panels.Items[1].Text:='Files: '+IntToStr(dat_header.Files);
+        Form1.statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(dat_header.Extensions);
+        Form1.menu_tools.Enabled:=True;
+        Form1.menu_extract.Enabled:=True;
+
+        IF Form1.MDIChildCount>0 THEN
+          FOR i:=0 TO Form1.MDIChildCount-1 DO BEGIN
+            IF Pos('binedit',Form1.MDIChildren[i].Name)>0 THEN
+              TForm8(Form1.MDIChildren[i]).Recreatelist;
+            IF Pos('preview',Form1.MDIChildren[i].Name)>0 THEN
+              TForm5(Form1.MDIChildren[i]).Recreatelist;
+            IF Pos('txmpreplace',Form1.MDIChildren[i].Name)>0 THEN
+              TForm7(Form1.MDIChildren[i]).Recreatelist;
+          END;
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+Form1.fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+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);
+  BEGIN
+    LoadDat;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  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;
+
+{##### Window-Menu-Handlers #####}
+PROCEDURE TForm1.menu_windows_cascadeClick(Sender: TObject);
+  BEGIN
+    Form1.Cascade;
+  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;
+  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;
+  END;
+
+
+
+PROCEDURE TForm1.open_child(window_context:String);
+  VAR
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i,j: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 BEGIN
+        caption:='Binary .dat-Editor '+IntToStr(i);
+        binEdit:=TForm8.Create(Application);
+        binEdit.Name:=name;
+        binEdit.Caption:=caption;
+        binEdit.Recreatelist;
+      END;
+      IF window_context='preview' THEN BEGIN
+        caption:='Preview-Window '+IntToStr(i);
+        preview:=TForm5.Create(Application);
+        preview.Name:=name;
+        preview.Caption:=caption;
+        preview.Recreatelist;
+      END;
+      IF window_context='txmpreplace' THEN BEGIN
+        caption:='TXMP Replacer '+IntToStr(i);
+        txmpreplacer:=TForm7.Create(Application);
+        txmpreplacer.Name:=name;
+        txmpreplacer.Caption:=caption;
+        txmpreplacer.Recreatelist;
+      END;
+
+      menu_button:=TMenuItem.Create(menu_windows);
+      menu_button.Caption:=caption;
+      menu_button.Name:='menu_window_'+name;
+      menu_button.OnClick:=Form1.menu_window_entryClick;
+      FOR j:=0 TO menu_windows.Count DO BEGIN
+        IF j<menu_windows.Count THEN BEGIN
+          IF Pos(window_context,menu_windows.Items[j].Name)>0 THEN BEGIN
+            IF StrToInt(RightStr(menu_windows.Items[j].Name,1))>i THEN BEGIN
+              menu_windows.Insert(j,menu_button);
+              Break;
+            END;
+          END;
+        END ELSE BEGIN
+          menu_windows.Add(menu_button);
+        END;
+      END;
+      IF MDIChildCount=9 THEN menu_tools.Enabled:=False;
+    END;
+  END;
+
+
+PROCEDURE TForm1.menu_windows_tileClick(Sender: TObject);
+  BEGIN
+    Form1.TileMode:=tbHorizontal;
+    Form1.Tile;
+  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;
+    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;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.18a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.18a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,255 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, SQLiteTable3, Unit3_data, Unit4_Exporters;
+
+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 LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+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
+    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 LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    //ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      //ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.18a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.18a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,85 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.18a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+    opened:Boolean;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  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;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.18a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.18a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,181 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+    {
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+    }
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(filename,fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+    {
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.18a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.18a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.18a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,155 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 300
+  Height = 200
+  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
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 173
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_preview: TPanel
+    Left = 159
+    Top = 0
+    Width = 133
+    Height = 173
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object img: TImage
+      Left = 0
+      Top = 20
+      Width = 133
+      Height = 153
+      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 = 133
+      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 = 173
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 148
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 148
+      Width = 150
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        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 = 0
+        OnClick = combo_extensionClick
+      end
+    end
+  end
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 144
+    Top = 24
+  end
+end
Index: /oup/releases/0.18a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.18a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,261 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    timer: TTimer;
+    panel_preview: TPanel;
+    img: TImage;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    Splitter1: TSplitter;
+    lbl_notpossible: TLabel;
+    PROCEDURE Recreatelist;
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE PreviewTXAN;
+    PROCEDURE PreviewTXMB;
+    PROCEDURE PreviewTXMP;
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    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;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(dat_header.Files)+')');
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      WITH dat_extensionsmap[i] DO BEGIN
+        combo_extension.Items.Add(
+          Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+
+          IntToStr(ExtCount)+')');
+      END;
+    END;
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  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;
+    Self.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[_fileid].Extension='TXAN' THEN PreviewTXAN
+    ELSE
+    IF dat_files[_fileid].Extension='TXMB' THEN PreviewTXMB
+    ELSE
+    IF dat_files[_fileid].Extension='TXMP' THEN PreviewTXMP
+    ELSE BEGIN
+      Self.lbl_notpossible.Visible:=True;
+      Self.img.Visible:=False;
+    END;
+  END;
+
+
+PROCEDURE TForm5.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+
+PROCEDURE TForm5.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF (dat_files[i].FileType AND $02)=0 THEN
+          list.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          IF (dat_files[i].FileType AND $02)=0 THEN
+            list.Items.Add(dat_files[i].FileName);
+    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 '+dat_files[_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 '+dat_files[_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 '+dat_files[_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);
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=0 TO Form1.menu_windows.Count-1 DO BEGIN
+      IF Form1.menu_windows.Items[i].Name='menu_window_'+Self.Name THEN BEGIN
+        Form1.menu_windows.Items[i].Free;
+        Break;
+      END;
+    END;
+    Form1.menu_tools.Enabled:=True;
+    Action:=caFree;
+  END;
+
+
+END.
Index: /oup/releases/0.18a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.18a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,398 @@
+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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,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.18a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.18a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.18a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,163 @@
+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
+  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 = 149
+        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
+    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
+end
Index: /oup/releases/0.18a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.18a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,226 @@
+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;
+    image_txmppreview: TImage;
+    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;
+    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
+    i:LongWord;
+  BEGIN
+    list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    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;
+    datfile: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);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Read(oldfading,1);
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Read(olddepth,1);
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Read(oldstore,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Read(old_rawaddr,4);
+      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;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datbyte:=$10;
+      IF check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      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);
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=0 TO Form1.menu_windows.Count-1 DO BEGIN
+      IF Form1.menu_windows.Items[i].Name='menu_window_'+Self.Name THEN BEGIN
+        Form1.menu_windows.Items[i].Free;
+        Break;
+      END;
+    END;
+    Form1.menu_tools.Enabled:=True;
+    Action:=caFree;
+  END;
+
+END.
Index: /oup/releases/0.18a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.18a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.18a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,204 @@
+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
+  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 = 300
+      Width = 483
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 100
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 483
+      Height = 300
+      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
+      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 = 309
+      Width = 483
+      Height = 114
+      Align = alClient
+      DefaultColWidth = 92
+      DefaultRowHeight = 18
+      FixedCols = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine]
+      TabOrder = 1
+      OnClick = structsClick
+    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 = 315
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 315
+      Width = 150
+      Height = 44
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object Label1: TLabel
+        Left = 2
+        Top = 4
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = 'Filter by extension:'
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 20
+        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 = 0
+        OnClick = combo_extensionClick
+      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
+end
Index: /oup/releases/0.18a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.18a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,354 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls,
+  Unit3_data, Unit2_functions, Unit9_data_structures, Unit4_exporters;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    Label1: TLabel;
+    combo_extension: TComboBox;
+    Bevel1: TBevel;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    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);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    FUNCTION GetValue(datatype:Byte; 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 listClick(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE Recreatelist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  fileid:LongWord;
+
+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:Byte; offset:LongWord):String;
+  VAR
+    data:Tdata;
+  BEGIN
+    CASE datatype OF
+      1: Result:=IntToStr(Self.hex.data[offset]);
+      2: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256);
+      3: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256);
+      4: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256+Self.hex.data[offset+3]*256*256*256);
+      5: Result:='0x'+IntToHex(Self.hex.data[offset],2);
+      6: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256,4);
+      7: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256,6);
+      8: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256+Self.hex.data[offset+3]*256*256*256,8);
+      9: BEGIN
+          SetLength(data,4);
+          data[0]:=Self.hex.data[offset];
+          data[1]:=Self.hex.data[offset+1];
+          data[2]:=Self.hex.data[offset+2];
+          data[3]:=Self.hex.data[offset+3];
+          Result:=FloatToStr(Decode_Float(data));
+        END;
+      10: Result:=IntToBin(Self.hex.data[offset]);
+    END;
+  END;
+
+PROCEDURE TForm8.WriteStructureInfos(structinfoid:Integer);
+  VAR
+    i:Byte;
+  BEGIN
+    IF structinfoid>=0 THEN BEGIN
+      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);
+          Self.structs.Cells[3,i]:=Self.GetValue(entries[i-1].datatype,entries[i-1].offset);
+          Self.structs.Cells[4,i]:=entries[i-1].description;
+        END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(dat_header.Files)+')');
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      WITH dat_extensionsmap[i] DO BEGIN
+        combo_extension.Items.Add(
+          Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+
+          IntToStr(ExtCount)+')');
+      END;
+    END;
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm8.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    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;
+    Self.panel_dataResize(Self);
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+dat_files[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;
+          SaveDatFile(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.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);
+    mem:=TMemoryStream.Create;
+    mem.Write(data[0],Length(data));
+    hex.LoadFromStream(mem);
+    mem.Free;
+    WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  END;
+
+PROCEDURE TForm8.ClearStructViewer;
+  VAR
+    x:Word;
+  BEGIN
+    structs.RowCount:=2;
+    FOR x:=0 TO structs.ColCount-1 DO structs.Cells[x,1]:='';
+  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(dat_files[fileid].extension)].entries[structs.Row-1].offset;
+      length:=GetTypeDataLength(structure_infos[GetStructureInfoId(dat_files[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;
+  END;
+
+PROCEDURE TForm8.hexChange(Sender: TObject);
+  BEGIN
+    IF hex.DataSize>0 THEN
+      WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  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(dat_files[fileid].Extension)>=0 THEN BEGIN
+        WITH structure_infos[GetStructureInfoId(dat_files[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;
+    END;
+  END;
+
+PROCEDURE TForm8.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm8.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF (dat_files[i].FileType AND $02)=0 THEN
+          list.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          IF (dat_files[i].FileType AND $02)=0 THEN
+            list.Items.Add(dat_files[i].FileName);
+    END;
+    IF list.Count>0 THEN BEGIN
+      list.ItemIndex:=0;
+      listClick(Self);
+    END;
+  END;
+
+PROCEDURE TForm8.FormClose(Sender: TObject; var Action: TCloseAction);
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=0 TO Form1.menu_windows.Count-1 DO BEGIN
+      IF Form1.menu_windows.Items[i].Name='menu_window_'+Self.Name THEN BEGIN
+        Form1.menu_windows.Items[i].Free;
+        Break;
+      END;
+    END;
+    Form1.menu_tools.Enabled:=True;
+    Action:=caFree;
+  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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    saved.DefaultExt:=dat_files[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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    IF opend.Execute THEN BEGIN
+      fs:=TFileStream.Create(opend.FileName,fmOpenRead);
+      IF fs.Size<>dat_files[fileid].size 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(dat_files[fileid].size)+CrLf+
+                    'Size of chosen file: '+FormatFileSize(fs.Size));
+      END ELSE BEGIN
+        SetLength(data,fs.Size);
+        fs.Read(data[0],fs.Size);
+        fs.Free;
+        fs:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+        fs.Seek(dat_files[fileid].dataddr,soFromBeginning);
+        fs.Write(data[0],Length(data));  
+      END;
+      fs.Free;
+      listClick(Self);
+    END;
+  END;
+
+END.
Index: /oup/releases/0.18a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.18a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.18a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,113 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils;
+
+TYPE
+  Tstructure_entry=RECORD
+      name:String;
+      offset:LongWord;
+      datatype:Byte;  // 1..4: Integer[1..4] dec; 5..8: Integer[1..4] hex; 9: float; 10: bitset; 11+: string[1+]
+      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:Byte):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+FUNCTION GetTypeDataLength(datatype:Byte):Byte;
+
+
+
+IMPLEMENTATION
+
+FUNCTION GetTypeDataLength(datatype:Byte):Byte;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11..255: Result:=datatype-10;
+    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:Byte):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';
+      11..255: Result:='String('+IntToStr(typeid-10)+')';
+    END;
+  END;
+
+
+PROCEDURE AddEntry(_ext:String; _name:String; _offset:LongWord; _datatype:Byte; _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:='TXMP';
+        typedesc:='Texture';
+      END;
+    END;
+  END;
+
+
+BEGIN
+  AddExtension('TXMP','Texture');
+  AddEntry('TXMP','ID',$00,8,'ID of this file');
+  AddEntry('TXMP','LevelID',$04,8,'ID of the level this file is in');
+  AddEntry('TXMP','FileName',$08,138,'');
+  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.
Index: /oup/releases/0.18a2/_changelog.txt
===================================================================
--- /oup/releases/0.18a2/_changelog.txt	(revision 8)
+++ /oup/releases/0.18a2/_changelog.txt	(revision 8)
@@ -0,0 +1,33 @@
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.18a2/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.18a2/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.18a2/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.18a2/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.18a2/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.18a2/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,16 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.18a2/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.18a2/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.18a2/src/OniUnPacker.cfg	(revision 8)
@@ -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.18a2/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.18a2/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.18a2/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,21 @@
+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';
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.Run;
+END.
Index: /oup/releases/0.18a2/src/SQLite3.pas
===================================================================
--- /oup/releases/0.18a2/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.18a2/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.18a2/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.18a2/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.18a2/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,883 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.18a2/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.18a2/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.18a2/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,148 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 544
+  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
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object statbar: TStatusBar
+    Left = 0
+    Top = 527
+    Width = 692
+    Height = 17
+    BiDiMode = bdLeftToRight
+    Panels = <
+      item
+        Text = 'Current .dat: -'
+        Width = 500
+      end
+      item
+        Text = 'Files: -'
+        Width = 90
+      end
+      item
+        Text = 'Extensions: -'
+        Width = 100
+      end>
+    ParentBiDiMode = False
+  end
+  object tabs: TTabSet
+    Left = 0
+    Top = 507
+    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 fopen: TOpenDialog
+    Filter = 'Oni-Dat-Files|*.dat|Oni-Sep-Files (MAC)|*.sep'
+    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_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_extract: TMenuItem
+      Caption = '&Extract/Convert'
+      Enabled = False
+      Visible = False
+      object menu_extractfile: TMenuItem
+        Caption = 'Convert and extract current &file'
+      end
+      object menu_extractlist: TMenuItem
+        Caption = 'Convert and extract all files currently in &list'
+      end
+      object menu_extractall: TMenuItem
+        Caption = 'Convert and extract &all files'
+      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
+    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
+end
Index: /oup/releases/0.18a2/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,370 @@
+UNIT Unit1_main;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Clipbrd, ExtCtrls, ComCtrls, Menus,
+  Unit2_functions, Unit3_data, Unit5_preview, Unit7_txmpreplace, Unit8_binedit,
+  Grids, MPHexEditor, ToolWin, ImgList, Tabs;
+
+TYPE
+  TForm1 = Class(TForm)
+    fopen: TOpenDialog;
+    menu: TMainMenu;
+    menu_main: TMenuItem;
+    menu_exit: TMenuItem;
+    menu_preview: TMenuItem;
+    menu_tools: TMenuItem;
+    menu_txmpreplace: TMenuItem;
+    menu_extract: TMenuItem;
+    menu_extractfile: TMenuItem;
+    menu_extractlist: TMenuItem;
+    menu_extractall: TMenuItem;
+    menu_loaddat: TMenuItem;
+    menu_sep1: TMenuItem;
+    menu_binedit: TMenuItem;
+    statbar: TStatusBar;
+    menu_windows: TMenuItem;
+    menu_windows_cascade: TMenuItem;
+    menu_windows_closeall: TMenuItem;
+    menu_sep2: TMenuItem;
+    menu_windows_tile: TMenuItem;
+    menu_sep3: TMenuItem;
+    menu_windows_next: TMenuItem;
+    menu_windows_previous: TMenuItem;
+    tabs: TTabSet;
+    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 LoadDat;
+  VAR i:LongWord;
+  BEGIN
+    Form1.fopen.InitialDir:=AppSettings.DatPath;
+    IF Form1.fopen.Execute THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(Form1.fopen.FileName)+')';
+      AppSettings.DatPath:=ExtractFilepath(Form1.fopen.FileName);
+      IF LoadDatInfos(Form1.fopen.FileName) THEN BEGIN
+        Form1.statbar.Panels.Items[0].Text:='Current .dat: '+dat_FileName;
+        Form1.statbar.Panels.Items[1].Text:='Files: '+IntToStr(dat_header.Files);
+        Form1.statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(dat_header.Extensions);
+        Form1.menu_tools.Enabled:=True;
+        Form1.menu_extract.Enabled:=True;
+
+        IF Form1.MDIChildCount>0 THEN
+          FOR i:=0 TO Form1.MDIChildCount-1 DO BEGIN
+            IF Pos('binedit',Form1.MDIChildren[i].Name)>0 THEN
+              TForm8(Form1.MDIChildren[i]).Recreatelist;
+            IF Pos('preview',Form1.MDIChildren[i].Name)>0 THEN
+              TForm5(Form1.MDIChildren[i]).Recreatelist;
+            IF Pos('txmpreplace',Form1.MDIChildren[i].Name)>0 THEN
+              TForm7(Form1.MDIChildren[i]).Recreatelist;
+          END;
+      END ELSE BEGIN
+        ShowMessage('Error while loading the file:'+CrLf+Form1.fopen.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    END;
+  END;
+
+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);
+  BEGIN
+    LoadDat;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  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;
+
+{#################################}
+{#####  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;
+    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);
+
+      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;
+
+      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.18a2/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,255 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, SysUtils, StrUtils, Math, SQLiteTable3, Unit3_data, Unit4_Exporters;
+
+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 LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+
+
+
+IMPLEMENTATION
+
+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
+    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 LoadDatInfos(filename:String):Boolean;
+  VAR i:LongWord;
+    dat_file:TFileStream;
+  BEGIN
+    Result:=True;
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+
+
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  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;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=True;
+    filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+    filestream.Seek(address,soFromBeginning);
+    filestream.Read(target^,size);
+    filestream.Free;
+  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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    Result:=export_noerror;
+
+    //ExportDefFileHeader(fileid);
+
+    IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+      //ExportDatFile(fileid);
+
+      FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+        IF i<=Length(ExportHandlers) THEN BEGIN
+          IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+            IF ExportHandlers[i].needed THEN BEGIN
+              CASE ExportHandlers[i].Handler(fileid,convert) OF
+                0: Result:=0;
+              ELSE
+                Result:=export_handlererror;
+              END;
+            END;
+            Break;
+          END;
+        END ELSE BEGIN
+          Result:=export_nohandler;
+        END;
+      END;
+    END;
+  END;
+
+
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+END.
Index: /oup/releases/0.18a2/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,85 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.18.2a';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+    opened:Boolean;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+VAR
+  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;
+
+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;
+
+IMPLEMENTATION
+
+END.
+
Index: /oup/releases/0.18a2/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,181 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+    {
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+    }
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(filename,fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+    {
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.18a2/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.18a2/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.18a2/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,156 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 300
+  Height = 200
+  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
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 173
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_preview: TPanel
+    Left = 159
+    Top = 0
+    Width = 133
+    Height = 173
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object img: TImage
+      Left = 0
+      Top = 20
+      Width = 133
+      Height = 153
+      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 = 133
+      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 = 173
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 148
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 148
+      Width = 150
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        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 = 0
+        OnClick = combo_extensionClick
+      end
+    end
+  end
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 144
+    Top = 24
+  end
+end
Index: /oup/releases/0.18a2/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,259 @@
+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;
+
+TYPE
+  TForm5 = Class(TForm)
+    timer: TTimer;
+    panel_preview: TPanel;
+    img: TImage;
+    panel_buttons: TPanel;
+    btn_dec: TButton;
+    btn_startstop: TButton;
+    btn_inc: TButton;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    Splitter1: TSplitter;
+    lbl_notpossible: TLabel;
+    procedure FormActivate(Sender: TObject);
+    PROCEDURE Recreatelist;
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE PreviewTXAN;
+    PROCEDURE PreviewTXMB;
+    PROCEDURE PreviewTXMP;
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    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;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(dat_header.Files)+')');
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      WITH dat_extensionsmap[i] DO BEGIN
+        combo_extension.Items.Add(
+          Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+
+          IntToStr(ExtCount)+')');
+      END;
+    END;
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  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;
+    Self.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[_fileid].Extension='TXAN' THEN PreviewTXAN
+    ELSE
+    IF dat_files[_fileid].Extension='TXMB' THEN PreviewTXMB
+    ELSE
+    IF dat_files[_fileid].Extension='TXMP' THEN PreviewTXMP
+    ELSE BEGIN
+      Self.lbl_notpossible.Visible:=True;
+      Self.img.Visible:=False;
+    END;
+  END;
+
+
+PROCEDURE TForm5.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+
+PROCEDURE TForm5.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF (dat_files[i].FileType AND $02)=0 THEN
+          list.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          IF (dat_files[i].FileType AND $02)=0 THEN
+            list.Items.Add(dat_files[i].FileName);
+    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 '+dat_files[_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 '+dat_files[_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 '+dat_files[_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.18a2/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,398 @@
+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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,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.18a2/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.18a2/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.18a2/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,164 @@
+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
+  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 = 149
+        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
+    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
+end
Index: /oup/releases/0.18a2/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,224 @@
+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;
+    image_txmppreview: TImage;
+    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;
+    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
+    i:LongWord;
+  BEGIN
+    list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    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;
+    datfile: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);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Read(oldfading,1);
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Read(olddepth,1);
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Read(oldstore,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Read(old_rawaddr,4);
+      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;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datbyte:=$10;
+      IF check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      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;
+
+END.
Index: /oup/releases/0.18a2/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.18a2/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.18a2/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,205 @@
+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
+  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 = 300
+      Width = 483
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 100
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 483
+      Height = 300
+      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
+      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 = 309
+      Width = 483
+      Height = 114
+      Align = alClient
+      DefaultColWidth = 92
+      DefaultRowHeight = 18
+      FixedCols = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine]
+      TabOrder = 1
+      OnClick = structsClick
+    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 = 315
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 315
+      Width = 150
+      Height = 44
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object Label1: TLabel
+        Left = 2
+        Top = 4
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = 'Filter by extension:'
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 20
+        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 = 0
+        OnClick = combo_extensionClick
+      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
+end
Index: /oup/releases/0.18a2/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,352 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls,
+  Unit3_data, Unit2_functions, Unit9_data_structures, Unit4_exporters;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    Label1: TLabel;
+    combo_extension: TComboBox;
+    Bevel1: TBevel;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    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);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    FUNCTION GetValue(datatype:Byte; 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 listClick(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE Recreatelist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  fileid:LongWord;
+
+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:Byte; offset:LongWord):String;
+  VAR
+    data:Tdata;
+  BEGIN
+    CASE datatype OF
+      1: Result:=IntToStr(Self.hex.data[offset]);
+      2: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256);
+      3: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256);
+      4: Result:=IntToStr(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256+Self.hex.data[offset+3]*256*256*256);
+      5: Result:='0x'+IntToHex(Self.hex.data[offset],2);
+      6: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256,4);
+      7: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256,6);
+      8: Result:='0x'+IntToHex(Self.hex.data[offset]+Self.hex.data[offset+1]*256+Self.hex.data[offset+2]*256*256+Self.hex.data[offset+3]*256*256*256,8);
+      9: BEGIN
+          SetLength(data,4);
+          data[0]:=Self.hex.data[offset];
+          data[1]:=Self.hex.data[offset+1];
+          data[2]:=Self.hex.data[offset+2];
+          data[3]:=Self.hex.data[offset+3];
+          Result:=FloatToStr(Decode_Float(data));
+        END;
+      10: Result:=IntToBin(Self.hex.data[offset]);
+    END;
+  END;
+
+PROCEDURE TForm8.WriteStructureInfos(structinfoid:Integer);
+  VAR
+    i:Byte;
+  BEGIN
+    IF structinfoid>=0 THEN BEGIN
+      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);
+          Self.structs.Cells[3,i]:=Self.GetValue(entries[i-1].datatype,entries[i-1].offset);
+          Self.structs.Cells[4,i]:=entries[i-1].description;
+        END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(dat_header.Files)+')');
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      WITH dat_extensionsmap[i] DO BEGIN
+        combo_extension.Items.Add(
+          Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+
+          IntToStr(ExtCount)+')');
+      END;
+    END;
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm8.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    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;
+    Self.panel_dataResize(Self);
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+dat_files[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;
+          SaveDatFile(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.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);
+    mem:=TMemoryStream.Create;
+    mem.Write(data[0],Length(data));
+    hex.LoadFromStream(mem);
+    mem.Free;
+    WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  END;
+
+PROCEDURE TForm8.ClearStructViewer;
+  VAR
+    x:Word;
+  BEGIN
+    structs.RowCount:=2;
+    FOR x:=0 TO structs.ColCount-1 DO structs.Cells[x,1]:='';
+  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(dat_files[fileid].extension)].entries[structs.Row-1].offset;
+      length:=GetTypeDataLength(structure_infos[GetStructureInfoId(dat_files[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;
+  END;
+
+PROCEDURE TForm8.hexChange(Sender: TObject);
+  BEGIN
+    IF hex.DataSize>0 THEN
+      WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  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(dat_files[fileid].Extension)>=0 THEN BEGIN
+        WITH structure_infos[GetStructureInfoId(dat_files[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;
+    END;
+  END;
+
+PROCEDURE TForm8.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm8.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF (dat_files[i].FileType AND $02)=0 THEN
+          list.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          IF (dat_files[i].FileType AND $02)=0 THEN
+            list.Items.Add(dat_files[i].FileName);
+    END;
+    IF list.Count>0 THEN BEGIN
+      list.ItemIndex:=0;
+      listClick(Self);
+    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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    saved.DefaultExt:=dat_files[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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    IF opend.Execute THEN BEGIN
+      fs:=TFileStream.Create(opend.FileName,fmOpenRead);
+      IF fs.Size<>dat_files[fileid].size 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(dat_files[fileid].size)+CrLf+
+                    'Size of chosen file: '+FormatFileSize(fs.Size));
+      END ELSE BEGIN
+        SetLength(data,fs.Size);
+        fs.Read(data[0],fs.Size);
+        fs.Free;
+        fs:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+        fs.Seek(dat_files[fileid].dataddr,soFromBeginning);
+        fs.Write(data[0],Length(data));  
+      END;
+      fs.Free;
+      listClick(Self);
+    END;
+  END;
+
+PROCEDURE TForm8.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+END.
Index: /oup/releases/0.18a2/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.18a2/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.18a2/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,113 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils;
+
+TYPE
+  Tstructure_entry=RECORD
+      name:String;
+      offset:LongWord;
+      datatype:Byte;  // 1..4: Integer[1..4] dec; 5..8: Integer[1..4] hex; 9: float; 10: bitset; 11+: string[1+]
+      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:Byte):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+FUNCTION GetTypeDataLength(datatype:Byte):Byte;
+
+
+
+IMPLEMENTATION
+
+FUNCTION GetTypeDataLength(datatype:Byte):Byte;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11..255: Result:=datatype-10;
+    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:Byte):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';
+      11..255: Result:='String('+IntToStr(typeid-10)+')';
+    END;
+  END;
+
+
+PROCEDURE AddEntry(_ext:String; _name:String; _offset:LongWord; _datatype:Byte; _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:='TXMP';
+        typedesc:='Texture';
+      END;
+    END;
+  END;
+
+
+BEGIN
+  AddExtension('TXMP','Texture');
+  AddEntry('TXMP','ID',$00,8,'ID of this file');
+  AddEntry('TXMP','LevelID',$04,8,'ID of the level this file is in');
+  AddEntry('TXMP','FileName',$08,138,'');
+  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.
Index: /oup/releases/0.19a/_changelog.txt
===================================================================
--- /oup/releases/0.19a/_changelog.txt	(revision 8)
+++ /oup/releases/0.19a/_changelog.txt	(revision 8)
@@ -0,0 +1,38 @@
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.19a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.19a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.19a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.19a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.19a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.19a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,20 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.530.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.540.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.10.28 00:20:57.420.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.pas</Transaction>
+    <Transaction>2005.10.28 00:20:57.440.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.dfm</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.19a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.19a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.19a/src/OniUnPacker.cfg	(revision 8)
@@ -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.19a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.19a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.19a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,24 @@
+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};
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.Run;
+END.
Index: /oup/releases/0.19a/src/SQLite3.pas
===================================================================
--- /oup/releases/0.19a/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.19a/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.19a/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.19a/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.19a/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,885 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  IF Pos('DROP TABLE ',SQL)>0 THEN Exit;
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.19a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.19a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.19a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.19a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.19a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,984 @@
+UNIT Unit10_leveldb;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ComCtrls, StdCtrls;
+
+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 SQLiteTable3, 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,mem:TMemoryStream;
+
+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;
+
+    DB:=TSQLiteDatabase.Create(FileName);
+    DB.ExecSQL('PRAGMA synchronous = 0;');
+    DB.ExecSQL('PRAGMA temp_store = 2;');
+    DB.ExecSQL('DROP TABLE globals;');
+    DB.ExecSQL('DROP TABLE linkmap;');
+    DB.ExecSQL('DROP TABLE rawmap;');
+    DB.ExecSQL('DROP TABLE datfiles;');
+    DB.ExecSQL('DROP TABLE extlist;');
+    DB.ExecSQL('VACUUM;');
+
+    DoStep('Creating tables');
+    progress.Position:=0;
+    lbl_progress.Caption:='';
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+    Application.ProcessMessages;
+
+    DB.ExecSQL('CREATE TABLE globals  (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR (20), value VARCHAR (50) );');
+    DB.ExecSQL('CREATE TABLE linkmap  (id INTEGER PRIMARY KEY AUTOINCREMENT, src_id INTEGER, src_link_offset INTEGER, target_id INTEGER );');
+    DB.ExecSQL('CREATE TABLE rawmap   (id INTEGER PRIMARY KEY AUTOINCREMENT, src_id INTEGER, src_link_offset INTEGER, data BLOB );');
+    DB.ExecSQL('CREATE TABLE datfiles (id INTEGER PRIMARY KEY, extension VARCHAR(4), name VARCHAR(128), contenttype INTEGER, data BLOB );');
+    DB.ExecSQL('CREATE TABLE extlist  (id INTEGER PRIMARY KEY AUTOINCREMENT, ext VARCHAR(4), ident VARCHAR(16) );');
+
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("dbversion","'+dbversion+'");');
+    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);
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("ident","'+temps+'");');
+    data:=LoadDatFile(0);
+    i:=data[7];
+    i:=i DIV 2;
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("lvl","'+IntToStr(i)+'");');
+
+    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];
+      DB.ExecSQL('INSERT INTO extlist (ext,ident) VALUES ("'+temps2+'","'+temps+'");');
+      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;
+
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      DB.ExecSQL('INSERT INTO datfiles (id,extension,name,contenttype) VALUES ('+IntToStr(i)+',"'+dat_files[i].Extension+'","'+dat_files[i].Name+'","'+IntToHex(dat_files[i].FileType,8)+'");');
+      IF (dat_files[i].FileType AND $02)=0 THEN BEGIN
+        dat_stream.Seek(dat_files[i].DatAddr,soFromBeginning);
+        mem:=TMemoryStream.Create;
+        mem.CopyFrom(dat_stream,dat_files[i].Size);
+        mem.Seek(0,soFromBeginning);
+        DB.UpdateBlob('UPDATE datfiles SET data = ? WHERE id='+IntToStr(i)+';',mem);
+        HandleFile(dat_files[i].Extension,i,True);
+        mem.Free;
+      END;
+      IF ( (i MOD 50)=0 ) AND (i>=100) THEN
+        lbl_estimation.Caption:='Estimated finishing time: '+TimeToStr((Time-begintime)/i*dat_header.Files+begintime);
+      IF (i MOD 5)=0 THEN BEGIN
+        progress.Position:=i;
+        lbl_progress.Caption:='Files done: '+IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        Application.ProcessMessages;
+      END;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    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;
+    DB.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)';
+    IF MessageBox(Self.Handle, PChar('Delete the unfinished DB-file?'), PChar('Delete file?'), MB_YESNO)=IDYES THEN BEGIN
+      DB.Free;
+      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(offset,size:LongWord; target:Pointer);
+  BEGIN
+    mem.Seek(offset,soFromBeginning);
+    mem.Read(target^,size);
+  END;
+
+PROCEDURE InsertDatLinkToDB(fileid:LongWord; offset:LongWord);
+  VAR
+    link:LongWord;
+  BEGIN
+    LoadFilePart(offset,4,@link);
+    IF link=0 THEN
+      link:=$FFFFFFFF
+    ELSE
+      link:=link DIV 256;
+    DB.ExecSQL('INSERT INTO linkmap (src_id,src_link_offset,target_id) VALUES ('+IntToStr(fileid)+','+IntToStr(offset)+','+IntToStr(link)+');');
+  END;
+
+PROCEDURE InsertRawFileToDB(fileid:LongWord; src_offset,raw_addr,size:LongWord);
+  VAR
+    localmem:TMemoryStream;
+  BEGIN
+    localmem:=TMemoryStream.Create;
+    filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+    filestream.Seek(raw_addr,soFromBeginning);
+    localmem.CopyFrom(filestream,size);
+    filestream.Free;
+    DB.ExecSQL('INSERT INTO rawmap (src_id,src_link_offset) VALUES ('+IntToStr(fileid)+','+IntToStr(src_offset)+');');
+    DB.UpdateBlob('UPDATE rawmap SET data = ? WHERE src_id='+IntToStr(fileid),localmem);
+    localmem.Free;
+  END;
+
+
+
+PROCEDURE AGDB(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart($1C,4,@links);
+      links:=links*2;
+      FOR i:=0 TO links-1 DO BEGIN
+        LoadFilePart($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($0C,4,@link);
+      LoadFilePart($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($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($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($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($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($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($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($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($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($08,4,@datasize);
+      LoadFilePart($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($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($40,4,@datasize);
+      LoadFilePart($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:LongWord;
+    data:Tdata;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart($18,4,@baselink);
+      LoadFilePart($1C,4,@links);
+      IF links>0 THEN BEGIN
+        FOR i:=0 TO links-1 DO BEGIN
+          LoadFilePart($20+i*4,4,@link);
+          SetLength(data,1024);
+          LoadRawFilePart(baselink+link,1024,@data[0]);
+          FOR j:=0 TO 1024 DO BEGIN
+            IF data[j]=$00 THEN Break;
+          END;
+          IF j<1024 THEN
+            InsertRawFileToDB(fileid,$20+i*4,baselink+link,j)
+          ELSE
+            ShowMessage('Error: Didn''t find message-end-marker...');
+        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($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($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;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 11 DO BEGIN
+        LoadFilePart($0C+i*4,4,@link);
+        InsertRawFileToDB(fileid,$0C+i*4,link,1{????????????????????????????????});
+      END;
+      LoadFilePart($13C,4,@link);
+      InsertRawFileToDB(fileid,$13C,link,1{????????????????????????????????});
+    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($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($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($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($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($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($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($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($8C,SizeOf(x),@x);
+      LoadFilePart($8E,SizeOf(y),@y);
+      LoadFilePart($90,SizeOf(storetype),@storetype);
+      LoadFilePart($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($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.19a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.19a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.19a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,210 @@
+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 = 371
+      Width = 187
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        Width = 183
+        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 = 0
+        OnClick = combo_extensionClick
+      end
+    end
+    object list: TListBox
+      Left = 2
+      Top = 15
+      Width = 187
+      Height = 356
+      Align = alClient
+      ItemHeight = 13
+      MultiSelect = True
+      TabOrder = 0
+    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 Label1: TLabel
+        Left = 8
+        Top = 40
+        Width = 265
+        Height = 17
+        AutoSize = False
+        Caption = 'Files done: 0/0'
+      end
+      object Label2: 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
+    end
+  end
+end
Index: /oup/releases/0.19a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.19a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit11_extractor.pas	(revision 8)
@@ -0,0 +1,146 @@
+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;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    list: TListBox;
+    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;
+    Label1: TLabel;
+    Label2: TLabel;
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE FormActivate(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE Extract(Sender: TObject);
+  PRIVATE
+  PUBLIC
+    PROCEDURE Recreatelist;
+  END;
+
+VAR
+  Form11: TForm11;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit2_functions, Unit3_data;
+
+PROCEDURE TForm11.Recreatelist;
+  VAR
+    i:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(dat_header.Files)+')');
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      WITH dat_extensionsmap[i] DO BEGIN
+        combo_extension.Items.Add(
+          Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+
+          IntToStr(ExtCount)+')');
+      END;
+    END;
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm11.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm11.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF (dat_files[i].FileType AND $02)=0 THEN
+          list.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          IF (dat_files[i].FileType AND $02)=0 THEN
+            list.Items.Add(dat_files[i].FileName);
+    END;
+  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;
+    files:LongWord;
+    i:LongWord;
+    fs:TFileStream;
+    ms:TMemoryStream;
+  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 sel_only THEN BEGIN
+      files:=list.SelCount;
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF list.Selected[i] THEN BEGIN
+          BEGIN END;
+        END;
+      END;
+    END ELSE BEGIN
+    END; 
+  END;
+
+END.
Index: /oup/releases/0.19a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.19a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.19a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,162 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 544
+  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
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object statbar: TStatusBar
+    Left = 0
+    Top = 527
+    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 = 507
+    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
+    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.19a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.19a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,425 @@
+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,
+  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;
+    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 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 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_convert.Enabled:=True;
+          menu_createdb.Enabled:=False;
+          menu_createlvl.Enabled:=True;
+        END ELSE menu_convert.Enabled:=False;
+      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.19a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.19a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,328 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math, SQLiteTable3,
+      Unit3_data, Unit4_Exporters;
+
+FUNCTION GetFilesList(ext:String; pattern:String):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 LoadDatInfos(filename:String):Boolean;
+FUNCTION LoadDatFile(fileid:LongWord):Tdata;
+PROCEDURE SaveDatFile(fileid:LongWord; data:Tdata);
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION ExportFile(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION GetWinFileName(fileid:LongWord; substring:String):String;
+FUNCTION GetExtractPath:String;
+PROCEDURE OpenDatabase(FileName:String);
+
+
+IMPLEMENTATION
+
+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
+    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 GetFilesList(ext:String; pattern:String):TStringList;
+  VAR
+    i:LongWord;
+  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(pattern,dat_files[i].FileName)>0) THEN BEGIN
+          SetLength(Result,Length(Result)+1);
+          Result[High(Result)]:=dat_files[i].FileName;
+        END;
+      END;
+    END ELSE BEGIN
+    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;
+{    FOR i:=0 TO High(dat_header.Ident2) DO
+      IF dat_header.Ident2[i]<>header_ident2[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;
+  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;
+  END;
+
+
+PROCEDURE SaveDatFile(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;
+  END;
+
+
+FUNCTION LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR dat_file:TFileStream;
+  BEGIN
+    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;
+  END;
+
+
+FUNCTION LoadRawFilePart(address,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead);
+      filestream.Seek(address,soFromBeginning);
+      filestream.Read(target^,size);
+      filestream.Free;
+    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; convert:Boolean):Integer;
+  VAR
+    i:Byte;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=export_noerror;
+      //ExportDefFileHeader(fileid);
+      IF (dat_files[fileid].FileType AND $02)=0 THEN BEGIN
+        //ExportDatFile(fileid);
+        FOR i:=1 TO Length(ExportHandlers)+1 DO BEGIN
+          IF i<=Length(ExportHandlers) THEN BEGIN
+            IF ExportHandlers[i].Ext=dat_files[fileid].Extension THEN BEGIN
+              IF ExportHandlers[i].needed THEN BEGIN
+                CASE ExportHandlers[i].Handler(fileid,convert) 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(fileid:LongWord; substring:String):String;
+  VAR
+    name:String;
+  BEGIN
+    name:=dat_files[fileid].Name;
+    name:=AnsiReplaceStr(name,'\','__');
+    name:=AnsiReplaceStr(name,'/','__');
+    name:=AnsiReplaceStr(name,'>','__');
+    name:=AnsiReplaceStr(name,'<','__');
+    Result:=FormatNumber(fileid,5,'0')+'-'+name+'.'+substring+'.'+dat_files[fileid].Extension;
+  END;
+
+FUNCTION GetExtractPath:String;
+  BEGIN
+    Result:=ExtractFilePath(dat_filename)+'\extracted_'+ExtractFileName(dat_filename);
+  END;
+
+
+PROCEDURE OpenDatabase(FileName:String);
+  VAR
+    i:Byte;
+    data:Tdata;
+    temps:String;
+    Tbl: TSQLiteTable;
+  BEGIN
+    IF NOT FileExists(FileName) THEN BEGIN
+      ShowMessage('File doesn''t exist!!!');
+      Exit;
+    END;
+    DB:=TSQLiteDatabase.Create(FileName);
+    Tbl:=DB.GetTable('SELECT name,value FROM globals ORDER BY name ASC');
+    REPEAT
+      IF Tbl.FieldAsString('name')='dbversion' THEN BEGIN
+        IF Tbl.FieldAsString('value')<>DBversion THEN BEGIN
+          ShowMessage('Database-file '+CrLf+'"'+FileName+'"'+CrLf+'has wrong version. (Required: '+DBversion+'; found: '+Tbl.FieldAsString('value')+')');
+          Exit;
+        END;
+      END;
+      IF Tbl.FieldAsString('name')='lvl' THEN BEGIN
+        database_level:=StrToInt(Tbl.FieldAsString('value'));
+      END;
+      IF Tbl.FieldAsString('name')='ident' THEN BEGIN
+        temps:=Tbl.FieldAsString('value');
+        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;
+      Tbl.Next;
+    UNTIL Tbl.EOF;
+    Tbl.Free;
+    opened_state:=opened_db;
+  END;
+
+
+
+
+END.
Index: /oup/releases/0.19a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.19a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,99 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes, SQLiteTable3;
+
+VAR
+  DB: TSQLiteDatabase;
+
+CONST
+  version:String='v0.19a';
+  dbversion:String='0.1';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+    opened:Boolean;
+  END;
+
+  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; convert:Boolean):Integer;
+  END;
+
+  TStringList=Array OF String;
+
+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.19a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.19a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,181 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+
+FUNCTION ExportTRAC(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXAN(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMB(fileid:LongWord; convert:Boolean):Integer;
+FUNCTION ExportTXMP(fileid:LongWord; convert:Boolean):Integer;
+VAR
+  ExportHandlers:Array[1..5] OF TExportHandlers=(
+    (Ext:'ABNA'; needed:False),
+    //(Ext:'AGDB'; needed:False),
+    (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 ExportDefLine(fileid:LongWord; line:String; create:Boolean);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    SetLength(data,Length(line)+2);
+    FOR i:=1 TO Length(line) DO
+      data[i-1]:=Ord(line[i]);
+    data[Length(line)]:=13;
+    data[Length(line)+1]:=10;
+    {
+    IF create THEN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmCreate)
+    ELSE BEGIN
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,'_DEF_'),fmOpenWrite);
+      filestream.Seek(0,soFromEnd);
+    END;
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+    }
+  END;
+
+PROCEDURE ExportDefFileHeader(fileid:LongWord);
+  BEGIN
+    IF NOT DirectoryExists(GetExtractPath) THEN
+      CreateDir(GetExtractPath);
+    WITH dat_files[fileid] DO
+    ExportDefLine(fileid,FormatNumber(fileid,5,'0')+':'+Name+':'+Extension+':'+IntToHex(Size,8)+':'+IntToHex(FileType,8),True);
+  END;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=LoadDatFile(fileid);
+    filestream:=TFileStream.Create(filename,fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+
+FUNCTION ExportTRAC;
+  VAR
+    link:LongWord;
+    linkcount:Word;
+    i:LongWord;
+  BEGIN
+    Result:=export_noerror;
+
+    LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+    ExportDefLine(fileid,FormatNumber(0,4,'0')+':LINKtoTRAC:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+
+    LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TRAMLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    FOR i:=1 TO linkcount DO BEGIN
+      LoadDatFilePart(fileid,$20+(i-1)*12+8,SizeOf(link),@link);
+      link:=link DIV 256;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTRAM:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    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);
+    ExportDefLine(fileid,'LOOPSPEED:'+FormatNumber(loop_speed,2,'0'),False);
+    ExportDefLine(fileid,'UNKNOWN:'+FormatNumber(unknown,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+  END;
+
+FUNCTION ExportTXMB;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    linkcount:LongWord;
+    link:LongWord;
+    width,height:Word;
+    cols,rows:Word;
+    i:Byte;
+    img:TImgPackage;
+    data:Tdata;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    LoadDatFilePart(fileid,$10,SizeOf(width),@width);
+    LoadDatFilePart(fileid,$12,SizeOf(height),@height);
+    LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    ExportDefLine(fileid,'WIDTH:'+FormatNumber(width,4,'0'),False);
+    ExportDefLine(fileid,'HEIGHT:'+FormatNumber(height,4,'0'),False);
+    ExportDefLine(fileid,'COLS:'+FormatNumber(cols,2,'0'),False);
+    ExportDefLine(fileid,'ROWS:'+FormatNumber(rows,2,'0'),False);
+
+    LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    ExportDefLine(fileid,'TXMPLINKS:'+FormatNumber(linkcount,4,'0'),False);
+    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;
+      ExportDefLine(fileid,FormatNumber(i,4,'0')+':LINKtoTXMP:'+FormatNumber(link,5,'0')+':'+dat_files[link].Name+':'+dat_files[link].Extension,False);
+    END;
+
+    IF convert THEN BEGIN
+      img:=LoadTXMBconnected(fileid);
+      data:=ImgdataToBmp(img.imgx,img.imgy,img.imgdepth,img.storetype,img.imgdata);
+      filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(data[0],Length(data));
+      filestream.Free;
+    END;
+  END;
+
+FUNCTION ExportTXMP;
+  VAR
+    filestream:TFileStream;
+    subfile:Byte;
+    img:TImgPackage;
+  BEGIN
+    Result:=export_noerror;
+    subfile:=1;
+
+    img:=LoadImgData(fileid);
+    {
+    filestream:=TFileStream.Create(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData'),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(GetExtractPath+'\'+GetWinFileName(fileid,FormatNumber(subfile,2,'0')+'-ImgData')+'.bmp',fmCreate);
+      filestream.Write(img.imgdata[0],Length(img.imgdata));
+      filestream.Free;
+    END;
+  END;
+
+END.
Index: /oup/releases/0.19a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.19a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.19a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,177 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 319
+  Height = 181
+  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 = 154
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_preview: TPanel
+    Left = 159
+    Top = 0
+    Width = 152
+    Height = 154
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object img: TImage
+      Left = 0
+      Top = 20
+      Width = 152
+      Height = 134
+      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 = 152
+      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 = 154
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 129
+      Align = alClient
+      ItemHeight = 13
+      PopupMenu = popup
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 129
+      Width = 150
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        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 = 0
+        OnClick = combo_extensionClick
+      end
+    end
+  end
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 144
+    Top = 24
+  end
+  object popup: TPopupMenu
+    AutoHotkeys = maManual
+    Left = 48
+    Top = 56
+    object popup_extractdat: TMenuItem
+      Caption = 'Extract .dat-file'
+      Enabled = False
+    end
+    object popup_extractdatraw: TMenuItem
+      Caption = 'Extract .dat-file and corresponding .raw-data'
+      Enabled = False
+    end
+    object popup_extractdatrawconvert: TMenuItem
+      Caption = 
+        'Extract .dat-file and corresponding .raw-data and convert if pos' +
+        'sible'
+      Enabled = False
+    end
+  end
+end
Index: /oup/releases/0.19a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.19a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,263 @@
+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;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    Splitter1: TSplitter;
+    lbl_notpossible: TLabel;
+    popup: TPopupMenu;
+    popup_extractdat: TMenuItem;
+    popup_extractdatraw: TMenuItem;
+    popup_extractdatrawconvert: TMenuItem;
+    procedure FormActivate(Sender: TObject);
+    PROCEDURE Recreatelist;
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE PreviewTXAN;
+    PROCEDURE PreviewTXMB;
+    PROCEDURE PreviewTXMP;
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    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;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(dat_header.Files)+')');
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      WITH dat_extensionsmap[i] DO BEGIN
+        combo_extension.Items.Add(
+          Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+
+          IntToStr(ExtCount)+')');
+      END;
+    END;
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  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;
+    Self.Caption:='Preview '+dat_files[_fileid].FileName;
+    IF dat_files[_fileid].Extension='TXAN' THEN PreviewTXAN
+    ELSE
+    IF dat_files[_fileid].Extension='TXMB' THEN PreviewTXMB
+    ELSE
+    IF dat_files[_fileid].Extension='TXMP' THEN PreviewTXMP
+    ELSE BEGIN
+      Self.lbl_notpossible.Visible:=True;
+      Self.img.Visible:=False;
+    END;
+  END;
+
+
+PROCEDURE TForm5.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+
+PROCEDURE TForm5.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF (dat_files[i].FileType AND $02)=0 THEN
+          list.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          IF (dat_files[i].FileType AND $02)=0 THEN
+            list.Items.Add(dat_files[i].FileName);
+    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 '+dat_files[_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 '+dat_files[_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 '+dat_files[_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.19a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.19a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,398 @@
+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,$9C,SizeOf(Result.raw_addr),@Result.raw_addr);
+    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);
+
+    LoadRawFilePart(Result.raw_addr,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.19a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.19a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.19a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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.19a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.19a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,242 @@
+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
+    i:LongWord;
+  BEGIN
+    list_txmp.Items.Clear;
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      IF (dat_files[i].Extension='TXMP') AND ((dat_files[i].FileType AND $02)=0) THEN
+        list_txmp.Items.Add(dat_files[i].FileName);
+    END;
+    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;
+    datfile: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);
+      datfile:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+
+      id:=StrToInt(MidStr(list_txmp.Items.Strings[list_txmp.ItemIndex],1,5));
+      dataddr:=dat_files[id].dataddr;
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Read(oldwidth,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Read(oldheight,2);
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Read(oldfading,1);
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Read(olddepth,1);
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Read(oldstore,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Read(old_rawaddr,4);
+      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;
+      datfile.Seek(dataddr+$88,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datbyte:=$10;
+      IF check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      datfile.Seek(dataddr+$89,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$8C,soFromBeginning);
+      datfile.Write(imgpkg.imgx,2);
+      datfile.Seek(dataddr+$8E,soFromBeginning);
+      datfile.Write(imgpkg.imgy,2);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      datfile.Seek(dataddr+$90,soFromBeginning);
+      datfile.Write(datbyte,1);
+      datfile.Seek(dataddr+$9C,soFromBeginning);
+      datfile.Write(new_rawaddr,4);
+      datfile.Free;
+
+      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.19a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.19a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.19a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,207 @@
+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 = 300
+      Width = 483
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 50
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 483
+      Height = 300
+      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
+      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 = 309
+      Width = 483
+      Height = 114
+      Align = alClient
+      DefaultColWidth = 92
+      DefaultRowHeight = 18
+      FixedCols = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      TabOrder = 1
+      OnClick = structsClick
+    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 = 315
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 315
+      Width = 150
+      Height = 44
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object lbl_filter: TLabel
+        Left = 2
+        Top = 4
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = '&Filter by extension:'
+        FocusControl = combo_extension
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 20
+        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 = 0
+        OnClick = combo_extensionClick
+      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
+end
Index: /oup/releases/0.19a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.19a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,413 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls,
+  Unit3_data, Unit2_functions, Unit9_data_structures, Unit4_exporters;
+
+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;
+{    PROCEDURE structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
+    PROCEDURE structsSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
+    PROCEDURE structsKeyPress(Sender: TObject; var Key: Char);
+}    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);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    FUNCTION GetValue(datatype:Byte; 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 listClick(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE Recreatelist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  fileid:LongWord;
+
+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:Byte; offset:LongWord):String;
+  VAR
+    data:Tdata;
+    i:Byte;
+  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]);
+      11..255: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-10 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);
+          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.Recreatelist;
+  VAR
+    i:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(dat_header.Files)+')');
+    FOR i:=0 TO dat_header.Extensions-1 DO BEGIN
+      WITH dat_extensionsmap[i] DO BEGIN
+        combo_extension.Items.Add(
+          Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+
+          IntToStr(ExtCount)+')');
+      END;
+    END;
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm8.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    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;
+    Self.panel_dataResize(Self);
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+dat_files[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;
+          SaveDatFile(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.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);
+    mem:=TMemoryStream.Create;
+    mem.Write(data[0],Length(data));
+    hex.LoadFromStream(mem);
+    mem.Free;
+    WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  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;
+  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(dat_files[fileid].extension)].entries[structs.Row-1].offset;
+      length:=GetTypeDataLength(structure_infos[GetStructureInfoId(dat_files[fileid].extension)].entries[structs.Row-1].datatype);
+      hex.SelStart:=offset;
+      hex.SelEnd:=offset+length-1;
+{      IF structs.Cells[structs.Col,0]='Value' THEN
+        IF structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype<=10 THEN
+          structs.Options:=structs.Options+[goEditing]
+      ELSE
+        structs.Options:=structs.Options-[goEditing];
+}    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;
+  END;
+
+PROCEDURE TForm8.hexChange(Sender: TObject);
+  BEGIN
+    IF hex.DataSize>0 THEN
+      WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  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(dat_files[fileid].Extension)>=0 THEN BEGIN
+        WITH structure_infos[GetStructureInfoId(dat_files[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;
+    END;
+  END;
+
+PROCEDURE TForm8.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm8.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF (dat_files[i].FileType AND $02)=0 THEN
+          list.Items.Add(dat_files[i].FileName);
+    END ELSE BEGIN
+      FOR i:=0 TO dat_header.Files-1 DO
+        IF dat_files[i].Extension=Extension THEN
+          IF (dat_files[i].FileType AND $02)=0 THEN
+            list.Items.Add(dat_files[i].FileName);
+    END;
+    IF list.Count>0 THEN BEGIN
+      list.ItemIndex:=0;
+      listClick(Self);
+    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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    saved.DefaultExt:=dat_files[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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    IF opend.Execute THEN BEGIN
+      fs:=TFileStream.Create(opend.FileName,fmOpenRead);
+      IF fs.Size<>dat_files[fileid].size 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(dat_files[fileid].size)+CrLf+
+                    'Size of chosen file: '+FormatFileSize(fs.Size));
+      END ELSE BEGIN
+        SetLength(data,fs.Size);
+        fs.Read(data[0],fs.Size);
+        fs.Free;
+        fs:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+        fs.Seek(dat_files[fileid].dataddr,soFromBeginning);
+        fs.Write(data[0],Length(data));  
+      END;
+      fs.Free;
+      listClick(Self);
+    END;
+  END;
+
+PROCEDURE TForm8.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+{
+PROCEDURE TForm8.structsKeyPress(Sender: TObject; VAR Key: Char);
+  VAR
+    dt:Byte;
+  BEGIN
+    IF structs.EditorMode THEN BEGIN
+      dt:=structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype;
+      CASE dt OF
+        1..4: BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'9']) THEN Key:=#0;
+              END;
+        5..8: BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'9','A'..'F','a'..'f']) THEN Key:=#0;
+                IF Key IN ['a'..'f'] THEN Key:=UpCase(Key);
+                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=2*(dt-4) ) THEN Key:=#0;
+              END;
+        9:    BEGIN
+                IF (Key IN ['.']) AND (Pos('.',structs.Cells[structs.Col,structs.Row])>0) THEN Key:=#0;
+                IF NOT (Key IN [#8,#13,#27,'0'..'9','.','-']) THEN Key:=#0;
+              END;
+        10:   BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'1']) THEN Key:=#0;
+                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=8 ) THEN Key:=#0;
+              END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.structsSetEditText(Sender: TObject; ACol, ARow: Integer; CONST Value: string);
+  BEGIN
+    IF NOT TWrapGrid(Sender).EditorMode THEN
+      ShowMessage('['+IntToStr(ACol)+'|'+IntToStr(ARow)+']='+Value);
+  END;
+
+PROCEDURE TForm8.structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
+  BEGIN
+    IF structs.EditorMode THEN
+      ShowMessage('EditorMode - '+Value)
+    ELSE
+      ShowMessage('NOT EditorMode - '+Value);
+  END;
+}
+END.
Index: /oup/releases/0.19a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.19a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.19a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,113 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils;
+
+TYPE
+  Tstructure_entry=RECORD
+      name:String;
+      offset:LongWord;
+      datatype:Byte;  // 1..4: Integer[1..4] dec; 5..8: Integer[1..4] hex; 9: float; 10: bitset; 11+: string[1+]
+      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:Byte):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+FUNCTION GetTypeDataLength(datatype:Byte):Byte;
+
+
+
+IMPLEMENTATION
+
+FUNCTION GetTypeDataLength(datatype:Byte):Byte;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11..255: Result:=datatype-10;
+    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:Byte):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';
+      11..255: Result:='String('+IntToStr(typeid-10)+')';
+    END;
+  END;
+
+
+PROCEDURE AddEntry(_ext:String; _name:String; _offset:LongWord; _datatype:Byte; _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:='TXMP';
+        typedesc:='Texture';
+      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,138,'');
+  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.
Index: /oup/releases/0.20a/_changelog.txt
===================================================================
--- /oup/releases/0.20a/_changelog.txt	(revision 8)
+++ /oup/releases/0.20a/_changelog.txt	(revision 8)
@@ -0,0 +1,42 @@
+OniUnPacker v0.20a
+------------------
++?
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.20a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.20a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.20a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.20a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.20a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.20a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,20 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.530.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.540.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.10.28 00:20:57.420.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.pas</Transaction>
+    <Transaction>2005.10.28 00:20:57.440.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.dfm</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.20a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.20a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.20a/src/OniUnPacker.cfg	(revision 8)
@@ -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.20a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.20a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.20a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,24 @@
+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};
+
+{$R *.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.Run;
+END.
Index: /oup/releases/0.20a/src/SQLite3.pas
===================================================================
--- /oup/releases/0.20a/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.20a/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.20a/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.20a/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.20a/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,885 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  IF Pos('DROP TABLE ',SQL)>0 THEN Exit;
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.20a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.20a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.20a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.20a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.20a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,986 @@
+UNIT Unit10_leveldb;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ComCtrls, StdCtrls;
+
+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 SQLiteTable3, 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,mem:TMemoryStream;
+
+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;
+
+    DB:=TSQLiteDatabase.Create(FileName);
+    DB.ExecSQL('PRAGMA synchronous = 0;');
+    DB.ExecSQL('PRAGMA temp_store = 2;');
+    DB.ExecSQL('DROP TABLE globals;');
+    DB.ExecSQL('DROP TABLE linkmap;');
+    DB.ExecSQL('DROP TABLE rawmap;');
+    DB.ExecSQL('DROP TABLE datfiles;');
+    DB.ExecSQL('DROP TABLE extlist;');
+    DB.ExecSQL('VACUUM;');
+
+    DoStep('Creating tables');
+    progress.Position:=0;
+    lbl_progress.Caption:='';
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+    Application.ProcessMessages;
+
+    DB.ExecSQL('CREATE TABLE globals  (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR (20), value VARCHAR (50) );');
+    DB.ExecSQL('CREATE TABLE linkmap  (id INTEGER PRIMARY KEY AUTOINCREMENT, src_id INTEGER, src_link_offset INTEGER, target_id INTEGER );');
+    DB.ExecSQL('CREATE TABLE rawmap   (id INTEGER PRIMARY KEY AUTOINCREMENT, src_id INTEGER, src_link_offset INTEGER, data BLOB );');
+    DB.ExecSQL('CREATE TABLE datfiles (id INTEGER PRIMARY KEY, extension VARCHAR(4), name VARCHAR(128), contenttype INTEGER, data BLOB );');
+    DB.ExecSQL('CREATE TABLE extlist  (id INTEGER PRIMARY KEY AUTOINCREMENT, ext VARCHAR(4), ident VARCHAR(16) );');
+
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("dbversion","'+dbversion+'");');
+    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);
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("ident","'+temps+'");');
+    data:=LoadDatFile(0);
+    i:=data[7];
+    i:=i DIV 2;
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("lvl","'+IntToStr(i)+'");');
+
+    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];
+      DB.ExecSQL('INSERT INTO extlist (ext,ident) VALUES ("'+temps2+'","'+temps+'");');
+      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;
+
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      DB.ExecSQL('INSERT INTO datfiles (id,extension,name,contenttype) VALUES ('+IntToStr(i)+',"'+dat_files[i].Extension+'","'+dat_files[i].Name+'","'+IntToHex(dat_files[i].FileType,8)+'");');
+      IF (dat_files[i].FileType AND $02)=0 THEN BEGIN
+        dat_stream.Seek(dat_files[i].DatAddr,soFromBeginning);
+        mem:=TMemoryStream.Create;
+        mem.CopyFrom(dat_stream,dat_files[i].Size);
+        mem.Seek(0,soFromBeginning);
+        DB.UpdateBlob('UPDATE datfiles SET data = ? WHERE id='+IntToStr(i)+';',mem);
+        HandleFile(dat_files[i].Extension,i,True);
+        mem.Free;
+      END;
+      IF ( (i MOD 50)=0 ) AND (i>=100) THEN
+        lbl_estimation.Caption:='Estimated finishing time: '+TimeToStr((Time-begintime)/i*dat_header.Files+begintime);
+      IF (i MOD 5)=0 THEN BEGIN
+        progress.Position:=i;
+        lbl_progress.Caption:='Files done: '+IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        Application.ProcessMessages;
+      END;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    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;
+    DB.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)';
+    IF MessageBox(Self.Handle, PChar('Delete the unfinished DB-file?'), PChar('Delete file?'), MB_YESNO)=IDYES THEN BEGIN
+      DB.Free;
+      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(offset,size:LongWord; target:Pointer);
+  BEGIN
+    mem.Seek(offset,soFromBeginning);
+    mem.Read(target^,size);
+  END;
+
+PROCEDURE InsertDatLinkToDB(fileid:LongWord; offset:LongWord);
+  VAR
+    link:LongWord;
+  BEGIN
+    LoadFilePart(offset,4,@link);
+    IF link=0 THEN
+      link:=$FFFFFFFF
+    ELSE
+      link:=link DIV 256;
+    DB.ExecSQL('INSERT INTO linkmap (src_id,src_link_offset,target_id) VALUES ('+IntToStr(fileid)+','+IntToStr(offset)+','+IntToStr(link)+');');
+  END;
+
+PROCEDURE InsertRawFileToDB(fileid:LongWord; src_offset,raw_addr,size:LongWord);
+  VAR
+    localmem:TMemoryStream;
+  BEGIN
+    localmem:=TMemoryStream.Create;
+    filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+    filestream.Seek(raw_addr,soFromBeginning);
+    localmem.CopyFrom(filestream,size);
+    filestream.Free;
+    DB.ExecSQL('INSERT INTO rawmap (src_id,src_link_offset) VALUES ('+IntToStr(fileid)+','+IntToStr(src_offset)+');');
+    DB.UpdateBlob('UPDATE rawmap SET data = ? WHERE src_id='+IntToStr(fileid),localmem);
+    localmem.Free;
+  END;
+
+
+
+PROCEDURE AGDB(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart($1C,4,@links);
+      links:=links*2;
+      FOR i:=0 TO links-1 DO BEGIN
+        LoadFilePart($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($0C,4,@link);
+      LoadFilePart($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($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($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($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($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($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($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($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($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($08,4,@datasize);
+      LoadFilePart($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($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($40,4,@datasize);
+      LoadFilePart($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:LongWord;
+    data:Tdata;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart($18,4,@baselink);
+      LoadFilePart($1C,4,@links);
+      IF links>0 THEN BEGIN
+        FOR i:=0 TO links-1 DO BEGIN
+          LoadFilePart($20+i*4,4,@link);
+          SetLength(data,1024);
+          LoadRawFile(fileid,baselink+link,1024,@data[0]);
+          FOR j:=0 TO 1024 DO BEGIN
+            IF (data[j]=$00) OR (j=1024) THEN BEGIN
+              IF j<1024 THEN
+                InsertRawFileToDB(fileid,$20+i*4,baselink+link,j)
+              ELSE
+                ShowMessage('Error: Didn''t find message-end-marker...');
+              Break;
+            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($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($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;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 11 DO BEGIN
+        LoadFilePart($0C+i*4,4,@link);
+        InsertRawFileToDB(fileid,$0C+i*4,link,1{????????????????????????????????});
+      END;
+      LoadFilePart($13C,4,@link);
+      InsertRawFileToDB(fileid,$13C,link,1{????????????????????????????????});
+    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($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($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($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($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($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($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($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($8C,SizeOf(x),@x);
+      LoadFilePart($8E,SizeOf(y),@y);
+      LoadFilePart($90,SizeOf(storetype),@storetype);
+      LoadFilePart($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($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.20a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.20a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.20a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,223 @@
+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 = 371
+      Width = 187
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        Width = 183
+        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 = 0
+        OnClick = combo_extensionClick
+      end
+    end
+    object list: TListBox
+      Left = 2
+      Top = 15
+      Width = 187
+      Height = 356
+      Align = alClient
+      ItemHeight = 13
+      MultiSelect = True
+      TabOrder = 0
+    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.20a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.20a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit11_extractor.pas	(revision 8)
@@ -0,0 +1,184 @@
+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;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    list: TListBox;
+    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;
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE FormActivate(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE Extract(Sender: TObject);
+  PRIVATE
+  PUBLIC
+    PROCEDURE Recreatelist;
+  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.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm11.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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 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
+            ExportFile(StrToInt(MidStr(list.Items.Strings[i],1,5)),list.Items.Strings[i],settings,'D:');
+            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
+          ExportFile(StrToInt(MidStr(list.Items.Strings[i],1,5)),list.Items.Strings[i],settings,'D:');
+          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:=done;
+            lbl_progress.Caption:='Files done: '+IntToStr(done)+'/'+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.20a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.20a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.20a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,167 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 544
+  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
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object statbar: TStatusBar
+    Left = 0
+    Top = 527
+    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 = 507
+    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.20a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.20a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,434 @@
+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 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 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.20a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.20a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,452 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math, SQLiteTable3,
+      Unit3_data, Unit4_Exporters;
+
+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 LoadDatInfos(filename:String):Boolean;
+PROCEDURE OpenDatabase(FileName:String);
+
+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
+
+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
+    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 GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringList;
+  VAR
+    i:LongWord;
+    where:String;
+    Tbl:TSQLiteTable;
+  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(pattern,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)=0)';
+      END;
+      IF Length(where)>0 THEN where:=' WHERE '+where;
+      Tbl:=DB.GetTable('SELECT id,name,extension FROM datfiles'+where+' ORDER BY id ASC;');
+      IF Tbl.Count>0 THEN BEGIN
+        SetLength(Result,Tbl.Count);
+        i:=0;
+        REPEAT
+          Result[i]:=FormatNumber(Tbl.FieldAsInteger('id'),5,'0')+'-'+Tbl.FieldAsString('name')+'.'+Tbl.FieldAsString('extension');
+          Inc(i);
+          Tbl.Next;
+        UNTIL Tbl.EOF;
+      END;
+    END;
+  END;
+
+FUNCTION GetExtensionsList:TStringList;
+  VAR
+    i:LongWord;
+    Tbl:TSQLiteTable;
+  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
+      Tbl:=DB.GetTable('SELECT extension,count(extension) AS x FROM datfiles GROUP BY extension ORDER BY extension ASC;');
+      IF Tbl.Count>0 THEN BEGIN
+        SetLength(Result,Tbl.Count);
+        i:=0;
+        REPEAT
+          Result[i]:=Tbl.FieldAsString('extension')+' ('+IntToStr(Tbl.FieldAsInteger('x'))+')';
+          Inc(i);
+          Tbl.Next;
+        UNTIL Tbl.EOF;
+      END;
+    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;
+    Tbl:TSQLiteTable;
+    mem:TMemoryStream;
+  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
+      Tbl:=DB.GetTable('SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';');
+      IF Tbl.Count>0 THEN BEGIN
+        mem:=Tbl.FieldAsBlob('data');
+        SetLength(Result,mem.Size);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(Result[0],mem.Size);
+        mem.Free;
+      END;
+    END;
+  END;
+PROCEDURE UpdateDatFile(fileid:LongWord; data:Tdata);
+  VAR
+    dat_file:TFileStream;
+    Tbl:TSQLiteTable;
+  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;
+    Tbl:TSQLiteTable;
+    mem:TMemoryStream;
+  BEGIN
+    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
+      Tbl:=DB.GetTable('SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';');
+      IF Tbl.Count>0 THEN BEGIN
+        Result:=True;
+        mem:=Tbl.FieldAsBlob('data');
+        mem.Seek(offset,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+    END;
+  END;
+FUNCTION UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR
+    dat_file:TFileStream;
+    Tbl:TSQLiteTable;
+  BEGIN
+    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;
+    Tbl:TSQLiteTable;
+    mem:TMemoryStream;
+  BEGIN
+    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
+      Tbl:=DB.GetTable('SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(datlinkoffset)+');');
+      IF Tbl.Count>0 THEN BEGIN
+        Result:=True;
+        mem:=Tbl.FieldAsBlob('data');
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+    END;
+  END;
+FUNCTION UpdateRawFile(fileid,datlinkoffset,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    raw_addr:LongWord;
+  BEGIN
+    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_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;
+
+
+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;
+    data:Tdata;
+    temps:String;
+    Tbl: TSQLiteTable;
+  BEGIN
+    IF NOT FileExists(FileName) THEN BEGIN
+      ShowMessage('File doesn''t exist!!!');
+      Exit;
+    END;
+    DB:=TSQLiteDatabase.Create(FileName);
+    Tbl:=DB.GetTable('SELECT name,value FROM globals ORDER BY name ASC');
+    REPEAT
+      IF Tbl.FieldAsString('name')='dbversion' THEN BEGIN
+        IF Tbl.FieldAsString('value')<>DBversion THEN BEGIN
+          ShowMessage('Database-file '+CrLf+'"'+FileName+'"'+CrLf+'has wrong version. (Required: '+DBversion+'; found: '+Tbl.FieldAsString('value')+')');
+          Exit;
+        END;
+      END;
+      IF Tbl.FieldAsString('name')='lvl' THEN BEGIN
+        database_level:=StrToInt(Tbl.FieldAsString('value'));
+      END;
+      IF Tbl.FieldAsString('name')='ident' THEN BEGIN
+        temps:=Tbl.FieldAsString('value');
+        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;
+      Tbl.Next;
+    UNTIL Tbl.EOF;
+    Tbl.Free;
+    opened_state:=opened_db;
+  END;
+
+
+
+
+END.
Index: /oup/releases/0.20a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.20a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,103 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes, SQLiteTable3;
+
+VAR
+  DB: TSQLiteDatabase;
+
+CONST
+  version:String='v0.20a';
+  dbversion:String='0.1';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+    opened:Boolean;
+  END;
+
+  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.20a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.20a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,185 @@
+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);
+    filestream:=TFileStream.Create(filename,fmCreate);
+    filestream.Write(data[0],Length(data));
+    filestream.Free;
+  END;
+
+FUNCTION ExportSNDD;
+  TYPE
+    TDatData=RECORD
+      _fileid:LongWord;
+      level:LongWord;
+      Flag:LongWord;
+      ChanNo:LongWord;
+      SampleRate:LongWord;
+      BytesPSec:LongWord;
+      BPSample:LongWord;
+      BitsPS:LongWord;
+      Unknown:Array[1..7] OF LongWord;
+      Unknown2:Word;
+      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;
+  	  WAV_Len:=RAWSize+70;
+  	  ASCII_WAV:=1163280727;
+    	ASCII_FMT:=544501094;
+	    WAV_FMT_Len:=50;
+    	ASCII_DATA:=1635017060;
+	    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.20a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.20a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.20a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,177 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 319
+  Height = 181
+  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 = 154
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_preview: TPanel
+    Left = 159
+    Top = 0
+    Width = 152
+    Height = 154
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object img: TImage
+      Left = 0
+      Top = 20
+      Width = 152
+      Height = 134
+      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 = 152
+      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 = 154
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 129
+      Align = alClient
+      ItemHeight = 13
+      PopupMenu = popup
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 129
+      Width = 150
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        Width = 145
+        Height = 21
+        Style = csDropDownList
+        DropDownCount = 12
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Tahoma'
+        Font.Style = []
+        ItemHeight = 0
+        ParentFont = False
+        Sorted = True
+        TabOrder = 0
+        OnClick = combo_extensionClick
+      end
+    end
+  end
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 144
+    Top = 24
+  end
+  object popup: TPopupMenu
+    AutoHotkeys = maManual
+    Left = 48
+    Top = 56
+    object popup_extractdat: TMenuItem
+      Caption = 'Extract .dat-file'
+      Enabled = False
+    end
+    object popup_extractdatraw: TMenuItem
+      Caption = 'Extract .dat-file and corresponding .raw-data'
+      Enabled = False
+    end
+    object popup_extractdatrawconvert: TMenuItem
+      Caption = 
+        'Extract .dat-file and corresponding .raw-data and convert if pos' +
+        'sible'
+      Enabled = False
+    end
+  end
+end
Index: /oup/releases/0.20a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.20a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,257 @@
+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;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    Splitter1: TSplitter;
+    lbl_notpossible: TLabel;
+    popup: TPopupMenu;
+    popup_extractdat: TMenuItem;
+    popup_extractdatraw: TMenuItem;
+    popup_extractdatrawconvert: TMenuItem;
+    procedure FormActivate(Sender: TObject);
+    PROCEDURE Recreatelist;
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE PreviewTXAN;
+    PROCEDURE PreviewTXMB;
+    PROCEDURE PreviewTXMP;
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    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.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.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+
+PROCEDURE TForm5.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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 '+dat_files[_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 '+dat_files[_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 '+dat_files[_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.20a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.20a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -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.20a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.20a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.20a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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.20a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.20a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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.20a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.20a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.20a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,207 @@
+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 = 300
+      Width = 483
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 50
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 483
+      Height = 300
+      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
+      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 = 309
+      Width = 483
+      Height = 114
+      Align = alClient
+      DefaultColWidth = 92
+      DefaultRowHeight = 18
+      FixedCols = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      TabOrder = 1
+      OnClick = structsClick
+    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 = 315
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 315
+      Width = 150
+      Height = 44
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object lbl_filter: TLabel
+        Left = 2
+        Top = 4
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = '&Filter by extension:'
+        FocusControl = combo_extension
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 20
+        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 = 0
+        OnClick = combo_extensionClick
+      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
+end
Index: /oup/releases/0.20a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.20a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,407 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls,
+  Unit3_data, Unit2_functions, Unit9_data_structures, Unit4_exporters;
+
+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;
+{    PROCEDURE structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
+    PROCEDURE structsSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
+    PROCEDURE structsKeyPress(Sender: TObject; var Key: Char);
+}    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);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    FUNCTION GetValue(datatype:Byte; 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 listClick(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE Recreatelist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  fileid:LongWord;
+
+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:Byte; offset:LongWord):String;
+  VAR
+    data:Tdata;
+    i:Byte;
+  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]);
+      11..255: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-10 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);
+          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.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.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    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;
+    Self.panel_dataResize(Self);
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+dat_files[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.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(dat_files[fileid].Extension));
+    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;
+  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(dat_files[fileid].extension)].entries[structs.Row-1].offset;
+      length:=GetTypeDataLength(structure_infos[GetStructureInfoId(dat_files[fileid].extension)].entries[structs.Row-1].datatype);
+      hex.SelStart:=offset;
+      hex.SelEnd:=offset+length-1;
+{      IF structs.Cells[structs.Col,0]='Value' THEN
+        IF structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype<=10 THEN
+          structs.Options:=structs.Options+[goEditing]
+      ELSE
+        structs.Options:=structs.Options-[goEditing];
+}    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;
+  END;
+
+PROCEDURE TForm8.hexChange(Sender: TObject);
+  BEGIN
+    IF hex.DataSize>0 THEN
+      WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  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(dat_files[fileid].Extension)>=0 THEN BEGIN
+        WITH structure_infos[GetStructureInfoId(dat_files[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;
+    END;
+  END;
+
+PROCEDURE TForm8.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm8.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    saved.DefaultExt:=dat_files[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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    IF opend.Execute THEN BEGIN
+      fs:=TFileStream.Create(opend.FileName,fmOpenRead);
+      IF fs.Size<>dat_files[fileid].size 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(dat_files[fileid].size)+CrLf+
+                    'Size of chosen file: '+FormatFileSize(fs.Size));
+      END ELSE BEGIN
+        SetLength(data,fs.Size);
+        fs.Read(data[0],fs.Size);
+        fs.Free;
+        fs:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+        fs.Seek(dat_files[fileid].dataddr,soFromBeginning);
+        fs.Write(data[0],Length(data));  
+      END;
+      fs.Free;
+      listClick(Self);
+    END;
+  END;
+
+PROCEDURE TForm8.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+{
+PROCEDURE TForm8.structsKeyPress(Sender: TObject; VAR Key: Char);
+  VAR
+    dt:Byte;
+  BEGIN
+    IF structs.EditorMode THEN BEGIN
+      dt:=structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype;
+      CASE dt OF
+        1..4: BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'9']) THEN Key:=#0;
+              END;
+        5..8: BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'9','A'..'F','a'..'f']) THEN Key:=#0;
+                IF Key IN ['a'..'f'] THEN Key:=UpCase(Key);
+                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=2*(dt-4) ) THEN Key:=#0;
+              END;
+        9:    BEGIN
+                IF (Key IN ['.']) AND (Pos('.',structs.Cells[structs.Col,structs.Row])>0) THEN Key:=#0;
+                IF NOT (Key IN [#8,#13,#27,'0'..'9','.','-']) THEN Key:=#0;
+              END;
+        10:   BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'1']) THEN Key:=#0;
+                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=8 ) THEN Key:=#0;
+              END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.structsSetEditText(Sender: TObject; ACol, ARow: Integer; CONST Value: string);
+  BEGIN
+    IF NOT TWrapGrid(Sender).EditorMode THEN
+      ShowMessage('['+IntToStr(ACol)+'|'+IntToStr(ARow)+']='+Value);
+  END;
+
+PROCEDURE TForm8.structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
+  BEGIN
+    IF structs.EditorMode THEN
+      ShowMessage('EditorMode - '+Value)
+    ELSE
+      ShowMessage('NOT EditorMode - '+Value);
+  END;
+}
+END.
Index: /oup/releases/0.20a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.20a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.20a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,113 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils;
+
+TYPE
+  Tstructure_entry=RECORD
+      name:String;
+      offset:LongWord;
+      datatype:Byte;  // 1..4: Integer[1..4] dec; 5..8: Integer[1..4] hex; 9: float; 10: bitset; 11+: string[1+]
+      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:Byte):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+FUNCTION GetTypeDataLength(datatype:Byte):Byte;
+
+
+
+IMPLEMENTATION
+
+FUNCTION GetTypeDataLength(datatype:Byte):Byte;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11..255: Result:=datatype-10;
+    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:Byte):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';
+      11..255: Result:='String('+IntToStr(typeid-10)+')';
+    END;
+  END;
+
+
+PROCEDURE AddEntry(_ext:String; _name:String; _offset:LongWord; _datatype:Byte; _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:='TXMP';
+        typedesc:='Texture';
+      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,138,'');
+  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.
Index: /oup/releases/0.21a/_changelog.txt
===================================================================
--- /oup/releases/0.21a/_changelog.txt	(revision 8)
+++ /oup/releases/0.21a/_changelog.txt	(revision 8)
@@ -0,0 +1,47 @@
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.21a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.21a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.21a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,171 @@
+﻿<?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.21a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.21a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.21a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,22 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.530.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.540.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.10.28 00:20:57.420.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.pas</Transaction>
+    <Transaction>2005.10.28 00:20:57.440.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.dfm</Transaction>
+    <Transaction>2005.12.18 11:32:06.823.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.pas</Transaction>
+    <Transaction>2005.12.18 11:32:06.833.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.dfm</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.21a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.21a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.21a/src/OniUnPacker.cfg	(revision 8)
@@ -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.21a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.21a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.21a/src/OniUnPacker.dpr	(revision 8)
@@ -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.21a/src/SQLite3.pas
===================================================================
--- /oup/releases/0.21a/src/SQLite3.pas	(revision 8)
+++ /oup/releases/0.21a/src/SQLite3.pas	(revision 8)
@@ -0,0 +1,120 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch)
+}
+
+interface
+
+const
+// Return values for sqlite3_exec() and sqlite3_step()
+
+SQLITE_OK   =        0;   // Successful result 
+SQLITE_ERROR =       1;   // SQL error or missing database 
+SQLITE_INTERNAL  =   2;   // An internal logic error in SQLite 
+SQLITE_PERM  =       3 ;  // Access permission denied 
+SQLITE_ABORT =       4;   // Callback routine requested an abort 
+SQLITE_BUSY  =       5;   // The database file is locked 
+SQLITE_LOCKED  =     6;   // A table in the database is locked 
+SQLITE_NOMEM =       7;   // A malloc() failed 
+SQLITE_READONLY  =   8;   // Attempt to write a readonly database 
+SQLITE_INTERRUPT  =  9;   // Operation terminated by sqlite3_interrupt()
+SQLITE_IOERR =      10;   // Some kind of disk I/O error occurred 
+SQLITE_CORRUPT =    11;   // The database disk image is malformed 
+SQLITE_NOTFOUND =   12;   // (Internal Only) Table or record not found 
+SQLITE_FULL    =    13;   // Insertion failed because database is full 
+SQLITE_CANTOPEN =   14;   // Unable to open the database file 
+SQLITE_PROTOCOL =   15;   // Database lock protocol error 
+SQLITE_EMPTY  =     16;   // Database is empty 
+SQLITE_SCHEMA  =    17;   // The database schema changed 
+SQLITE_TOOBIG   =   18;   // Too much data for one row of a table 
+SQLITE_CONSTRAINT = 19;   // Abort due to contraint violation 
+SQLITE_MISMATCH =   20;   // Data type mismatch 
+SQLITE_MISUSE  =    21;   // Library used incorrectly 
+SQLITE_NOLFS     =  22;   // Uses OS features not supported on host 
+SQLITE_AUTH   =     23;   // Authorization denied 
+SQLITE_FORMAT =     24;   // Auxiliary database format error 
+SQLITE_RANGE   =    25;   // 2nd parameter to sqlite3_bind out of range 
+SQLITE_NOTADB    =  26;   // File opened that is not a database file 
+SQLITE_ROW   =      100;  // sqlite3_step() has another row ready 
+SQLITE_DONE   =     101;  // sqlite3_step() has finished executing
+
+SQLITE_INTEGER  = 1;
+SQLITE_FLOAT  =  2;
+SQLITE_TEXT = 3;
+SQLITE_BLOB  =   4;
+SQLITE_NULL  =   5;
+ 
+type
+TSQLiteDB     = Pointer;
+TSQLiteResult = ^PChar;
+TSQLiteStmt = Pointer;
+
+function  SQLite3_Open           (dbname: PChar; var db: TSqliteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_open';
+function SQLite3_Close          (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_close';
+function  SQLite3_Exec           (db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_exec';
+function  SQLite3_Version        (): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_libversion';
+function  SQLite3_ErrMsg    (db: TSQLiteDB): PChar; cdecl; external 'sqlite3.dll' name 'sqlite3_errmsg';
+function SQLite3_ErrCode (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_errcode';
+procedure SQlite3_Free (P: PChar); cdecl; external 'sqlite3.dll' name 'sqlite3_free';
+function  SQLite3_GetTable       (db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_get_table';
+procedure SQLite3_FreeTable      (Table:TSQLiteResult ); cdecl; external 'sqlite3.dll' name 'sqlite3_free_table';
+function  SQLite3_Complete       (P: PChar): boolean; cdecl; external 'sqlite3.dll' name 'sqlite3_complete';
+function  SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external 'sqlite3.dll' name 'sqlite3_last_insert_rowid';
+procedure SQLite3_Interrupt         (db: TSQLiteDB); cdecl; external 'sqlite3.dll' name 'sqlite3_interrupt';
+procedure SQLite3_BusyHandler    (db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external 'sqlite3.dll' name'sqlite3_busy_handler' ;
+procedure SQLite3_BusyTimeout    (db: TSQLiteDB; TimeOut: integer); cdecl; external 'sqlite3.dll' name 'sqlite3_busy_timeout';
+function  SQLite3_Changes        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_changes';
+function  SQLite3_TotalChanges        (db: TSQLiteDB): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_total_changes';
+function SQLite3_Prepare (db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_prepare';
+function SQLite3_ColumnCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_count';
+function Sqlite3_ColumnName (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_name';
+function Sqlite3_ColumnDeclType (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_decltype';
+function Sqlite3_Step (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_step';
+function SQLite3_DataCount (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_data_count';
+
+function Sqlite3_ColumnBlob (hStmt: TSqliteStmt; ColNum: integer):pointer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_blob';
+function Sqlite3_ColumnBytes (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_bytes';
+function Sqlite3_ColumnDouble (hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external 'sqlite3.dll' name 'sqlite3_column_double';
+function Sqlite3_ColumnInt (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int';
+function Sqlite3_ColumnText (hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external 'sqlite3.dll' name 'sqlite3_column_text';
+function Sqlite3_ColumnType (hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_column_type';
+ // function Sqlite3_ColumnInt64 (hStmt: TSqliteStmt; ColNum: integer): SqliteInt64; cdecl; external 'sqlite3.dll' name 'sqlite3_column_int64';
+function SQLite3_Finalize (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_finalize';
+function SQLite3_Reset (hStmt: TSqliteStmt): integer; cdecl; external 'sqlite3.dll' name 'sqlite3_reset';
+
+//
+// In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
+// one or more literals can be replace by a wildcard "?" or ":N:" where
+// N is an integer.  These value of these wildcard literals can be set
+// using the routines listed below.
+//
+// In every case, the first parameter is a pointer to the sqlite3_stmt
+// structure returned from sqlite3_prepare().  The second parameter is the
+// index of the wildcard.  The first "?" has an index of 1.  ":N:" wildcards
+// use the index N.
+//
+ // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+ //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
+//text after SQLite has finished with it.  If the fifth argument is the
+// special value SQLITE_STATIC, then the library assumes that the information
+// is in static, unmanaged space and does not need to be freed.  If the
+// fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
+// own private copy of the data.
+//
+// The sqlite3_bind_* routine must be called before sqlite3_step() after
+// an sqlite3_prepare() or sqlite3_reset().  Unbound wildcards are interpreted
+// as NULL.
+//
+
+function SQLite3_BindBlob(hStmt: TSqliteStmt; ParamNum: integer;
+ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer;
+cdecl; external 'sqlite3.dll' name 'sqlite3_bind_blob';
+
+implementation
+
+end.
Index: /oup/releases/0.21a/src/SQLiteTable3.pas
===================================================================
--- /oup/releases/0.21a/src/SQLiteTable3.pas	(revision 8)
+++ /oup/releases/0.21a/src/SQLiteTable3.pas	(revision 8)
@@ -0,0 +1,885 @@
+unit SQLiteTable3;
+
+{
+  Simple classes for using SQLite's exec and get_table.
+
+  TSQLiteDatabase wraps the calls to open and close an SQLite database.
+  It also wraps SQLite_exec for queries that do not return a result set
+
+  TSQLiteTable wraps sqlite_get_table.
+  It allows accessing fields by name as well as index and can step through a
+  result set with the Next procedure.
+
+  Adapted by Tim Anderson (tim@itwriting.com)
+  Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+}
+
+interface
+
+uses
+  Windows, SQLite3, Classes, Sysutils;
+
+const
+  dtStr = 0;
+  dtInt = 1;
+  dtBool = 2;
+  dtNumeric = 3;
+  dtBlob = 4;
+
+type
+
+  ESQLiteException = class(Exception)
+  private
+  public
+  end;
+
+  TSQLiteTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: Boolean;
+    procedure RaiseError(s: string; SQL: string);
+
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    function GetTable(const SQL: string): TSQLiteTable;
+    procedure ExecSQL(const SQL: string);
+    procedure UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+
+  published
+    property isTransactionOpen: boolean read fInTrans;
+
+  end;
+
+  TSQLiteTable = class
+  private
+    fResults: TList;
+    fRowCount: Cardinal;
+    fColCount: Cardinal;
+    fCols: TStringList;
+    fColTypes: TList;
+    fRow: Cardinal;
+
+    function GetFields(I: Integer): string;
+    function GetEOF: Boolean;
+    function GetBOF: Boolean;
+    function GetColumns(I: Integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+    function GetCount: Integer;
+    function GetCountResult: Integer;
+
+
+  public
+    constructor Create(DB: TSQLiteDatabase; const SQL: string);
+    destructor Destroy; override;
+    function FieldAsInteger(FieldName: string): integer;
+    function FieldAsBool(FieldName: string): boolean;
+    function FieldAsBlob(FieldName: string): TMemoryStream;
+    function FieldAsBlobText(FieldName: string): string;
+    function FieldIsNull(FieldName: string): boolean;
+    function FieldAsString(FieldName: string): string;
+    function FieldAsDouble(FieldName: string): double;
+{    function FieldAsInteger(I: integer): integer;
+    function FieldAsBool(I: integer): boolean;
+    function FieldAsBlob(I: Integer): TMemoryStream;
+    function FieldAsBlobText(I: Integer): string;
+    function FieldIsNull(I: integer): boolean;
+    function FieldAsString(I: Integer): string;
+    function FieldAsDouble(I: Integer): double;
+}    function Next: Boolean;
+    function Previous: Boolean;
+    property EOF: Boolean read GetEOF;
+    property BOF: Boolean read GetBOF;
+    property Fields[I: Integer]: string read GetFields;
+    property FieldByName[FieldName: string]: string read GetFieldByName;
+    property FieldIndex[FieldName: string]: integer read GetFieldIndex;
+    property Columns[I: Integer]: string read GetColumns;
+    property ColCount: Cardinal read fColCount;
+    property RowCount: Cardinal read fRowCount;
+    property Row: Cardinal read fRow;
+    function MoveFirst: boolean;
+    function MoveLast: boolean;
+
+
+    property Count: Integer read GetCount;
+
+    // The property CountResult is used when you execute count(*) queries.
+    // It returns 0 if the result set is empty or the value of the
+    // first field as an integer.
+    property CountResult: Integer read GetCountResult;
+  end;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+implementation
+
+uses
+  strutils;
+
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+
+  if assigned(ptr) then
+  begin freemem(ptr) end;
+
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteDatabase
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+begin
+  inherited Create;
+
+  self.fInTrans := false;
+
+  Msg := nil;
+  try
+    iResult := SQLite3_Open(PChar(FileName), Fdb);
+
+    if iResult <> SQLITE_OK then
+    begin
+      if Assigned(Fdb) then
+      begin
+        Msg := Sqlite3_ErrMsg(Fdb);
+        raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
+      end
+      else
+      begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
+    end;
+
+    //set a few configs
+    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+
+    //this pragma not recommended and may disappear in future
+    //sqlite versions
+    //self.ExecSQL('PRAGMA full_column_names = 1;');
+
+  finally
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+
+end;
+
+
+//..............................................................................
+
+destructor TSQLiteDatabase.Destroy;
+begin
+
+  if self.fInTrans then
+  begin self.ExecSQL('ROLLBACK;') end; //assume rollback
+
+  if Assigned(fDB) then
+  begin SQLite3_Close(fDB) end;
+
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise and exception with an appropriate message
+var
+  Msg: PChar;
+begin
+
+  Msg := nil;
+
+  if sqlite3_errcode(self.fDB) <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  IF Pos('DROP TABLE ',SQL)>0 THEN Exit;
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.ExecSQL(const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+begin
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+  end;
+end;
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+  iBindResult: integer;
+begin
+//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
+
+  if pos('?', SQL) = 0 then
+  begin RaiseError('SQL must include a ? parameter', SQL) end;
+
+  Msg := nil;
+  try
+
+    if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+    if (Stmt = nil) then
+    begin RaiseError('Could not prepare SQL statement', SQL) end;
+
+//now bind the blob data
+    iSize := BlobData.size;
+
+    GetMem(ptr, iSize);
+
+    if (ptr = nil) then
+    begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
+
+    BlobData.position := 0;
+    BlobData.Read(ptr^, iSize);
+
+    iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
+
+    if iBindResult <> SQLITE_OK then
+    begin RaiseError('Error binding blob to database', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    if (iStepResult <> SQLITE_DONE) then
+    begin RaiseError('Error executing SQL statement', SQL) end;
+
+  finally
+
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+
+    if Assigned(Msg) then
+    begin SQLite3_Free(Msg) end;
+  end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
+begin
+  Result := TSQLiteTable.Create(Self, SQL);
+end;
+
+procedure TSQLiteDatabase.BeginTransaction;
+begin
+  if not self.fInTrans then
+  begin
+    self.ExecSQL('BEGIN TRANSACTION;');
+    self.fInTrans := true;
+  end
+  else
+  begin raise ESqliteException.Create('Transaction already open') end;
+end;
+
+procedure TSQLiteDatabase.Commit;
+begin
+  self.ExecSQL('COMMIT;');
+  self.fInTrans := false;
+end;
+
+procedure TSQLiteDatabase.Rollback;
+begin
+  self.ExecSQL('ROLLBACK;');
+  self.fInTrans := false;
+end;
+
+function TSQLiteDatabase.TableExists(TableName: string): boolean;
+var
+  sql: string;
+  ds: TSqliteTable;
+begin
+//returns true if table exists in the database
+  sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
+
+  try
+
+    ds := self.GetTable(sql);
+
+    result := (ds.Count > 0);
+
+  finally
+
+    freeandnil(ds);
+
+  end;
+
+end;
+
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+  iStepResult: integer;
+
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisBoolValue: pBoolean;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInteger;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+
+begin
+
+  try
+
+    self.fRowCount := 0;
+    self.fColCount := 0;
+
+//if there are several SQL statements in SQL, NextSQLStatment points to the
+//beginning of the next one. Prepare only prepares the first SQL statement.
+
+    if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+    begin Db.RaiseError('Error executing SQL', SQL) end;
+
+    if (Stmt = nil) then
+    begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
+
+    iStepResult := Sqlite3_step(Stmt);
+
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+
+            inc(fRowCount);
+
+            if (fRowCount = 1) then
+            begin
+     //get data types
+              fCols := TStringList.Create;
+              fCols.CaseSensitive := False;
+              fColTypes := TList.Create;
+
+              fColCount := SQLite3_ColumnCount(stmt);
+
+              for i := 0 to Pred(fColCount) do
+              begin
+                fCols.Add(Sqlite3_ColumnName(stmt, i));
+              end;
+
+              for i := 0 to Pred(fColCount) do
+              begin
+
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+
+                if DeclaredColType = nil then begin
+                //use the actual column type instead
+                //seems to be needed for last_insert_rowid
+                  thisColType^ := Sqlite3_ColumnType(stmt, i);
+                end else begin
+                  DeclaredColType := strupper(DeclaredColType);
+                  
+                  if DeclaredColType = 'INTEGER' then
+                  begin thisColType^ := dtInt end
+                  else
+                    if DeclaredColType = 'BOOLEAN' then
+                    begin thisColType^ := dtBool end
+                    else
+                      if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
+                      begin thisColType^ := dtNumeric end
+                      else
+                        if DeclaredColType = 'BLOB' then
+                        begin thisColType^ := dtBlob end
+                        else
+                        begin thisColType^ := dtStr end;
+                  end;
+
+                fColTypes.Add(thiscoltype);
+              end;
+
+              fResults := TList.Create;
+
+            end;
+
+     //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+              begin fResults.Add(nil) end
+              else
+              begin
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtBool then
+                  begin
+                    new(thisboolvalue);
+                    thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
+                    fResults.Add(thisboolvalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtNumeric then
+                    begin
+                      new(thisdoublevalue);
+                      thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                      fResults.Add(thisdoublevalue);
+                    end
+                    else
+                      if pInteger(fColTypes[i])^ = dtBlob then
+                      begin
+                        iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+
+                        if iNumBytes = 0 then
+                        begin thisblobvalue := nil end
+                        else
+                        begin
+                          thisblobvalue := TMemoryStream.Create;
+                          thisblobvalue.position := 0;
+                          ptr := Sqlite3_ColumnBlob(stmt, i);
+                          thisblobvalue.writebuffer(ptr^, iNumBytes);
+                        end;
+                        fResults.Add(thisblobvalue);
+
+                      end
+                      else
+                      begin
+                        new(thisstringvalue);
+                        ptrValue := Sqlite3_ColumnText(stmt, i);
+                        setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                        fResults.Add(thisstringvalue);
+                      end;
+              end;
+
+            end;
+
+
+
+          end;
+
+        SQLITE_BUSY:
+          begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
+      else
+        begin Db.RaiseError('Could not retrieve data', SQL) end;
+      end;
+
+      iStepResult := Sqlite3_step(Stmt);
+
+    end;
+
+    fRow := 0;
+
+  finally
+    if Assigned(Stmt) then
+    begin Sqlite3_Finalize(stmt) end;
+  end;
+
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var i: integer;
+  iColNo: integer;
+begin
+
+
+  if Assigned(fResults) then
+  begin for i := 0 to fResults.Count - 1 do
+    begin
+    //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+      dtBlob:
+          begin
+          TMemoryStream(fResults[i]).free;
+          end;
+      dtStr:
+          begin
+           if fResults[i] <> nil then
+           begin
+               setstring(string(fResults[i]^), nil, 0);
+               dispose(fResults[i]);
+           end;
+          end;
+      else
+        begin
+        dispose(fResults[i])
+        end;
+      end;
+    end;
+    fResults.Free;
+   end;
+
+    if Assigned(fCols) then
+    begin fCols.Free end;
+
+    if Assigned(fColTypes) then
+    begin for i := 0 to fColTypes.Count - 1 do
+      begin
+        dispose(fColTypes[i]);
+      end end;
+    fColTypes.Free;
+    inherited;
+  end;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: Integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: Integer;
+begin
+  if not EOF then
+  begin Result := StrToInt(Fields[0]) end
+  else
+  begin Result := 0 end;
+end;
+
+function TSQLiteTable.GetCount: Integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: Boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: Boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  result := fCols.IndexOf(FieldName);
+
+  if (result < 0) then
+  begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
+
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: Integer): string;
+var
+  thisvalue: pstring;
+  ptr: pointer;
+  thisboolvalue: pBoolean;
+  thistype: integer;
+begin
+  Result := '';
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+//integer and boolean types are not stored in the resultset
+//as strings, so they should be retrieved using the type-specific
+//methods
+
+  thistype := pInteger(self.fColTypes[I])^;
+
+  if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
+  begin
+    ptr := self.fResults[(self.frow * self.fColCount) + I];
+
+    if ptr <> nil then
+    begin
+      raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
+    end;
+
+  end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin
+      thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if thisboolvalue <> nil then
+      begin if thisboolvalue^ then
+        begin result := '1' end
+        else
+        begin result := '0' end end;
+    end
+
+    else
+
+    begin
+
+      thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+      if (thisvalue <> nil) then
+      begin Result := thisvalue^ end
+      else
+      begin Result := '' end; //return empty string
+    end;
+
+end;
+
+function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := nil end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+    begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
+    else
+    begin raise ESqliteException.Create('Not a Blob field') end;
+end;
+
+function TSqliteTable.FieldAsBlobText(FieldName: string): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+begin
+  result := '';
+
+  MemStream := self.FieldAsBlob(FieldName);
+
+  if MemStream <> nil then
+  begin if MemStream.Size > 0 then
+    begin
+      MemStream.position := 0;
+
+      Buffer := stralloc(MemStream.Size + 1);
+      MemStream.readbuffer(Buffer[0], MemStream.Size);
+      (Buffer + MemStream.Size)^ := chr(0);
+      SetString(Result, Buffer, MemStream.size);
+      strdispose(Buffer);
+    end end;
+
+end;
+
+
+function TSqliteTable.FieldAsInteger(FieldName: string): integer;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsDouble(FieldName: string): double;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := 0 end
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+    begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+      begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
+      else
+      begin raise ESqliteException.Create('Not an integer or numeric field') end;
+
+end;
+
+function TSqliteTable.FieldAsBool(FieldName: string): boolean;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := false end
+  else
+    if pInteger(self.fColTypes[I])^ = dtBool then
+    begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
+    else
+    begin raise ESqliteException.Create('Not a boolean field') end;
+end;
+
+function TSqliteTable.FieldAsString(FieldName: string): string;
+var
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+  begin result := '' end
+  else
+  begin result := self.GetFields(I) end;
+
+end;
+
+function TSqliteTable.FieldIsNull(FieldName: string): boolean;
+var
+  thisvalue: pointer;
+  i: Integer;
+begin
+
+  if EOF then
+  begin raise ESqliteException.Create('Table is at End of File') end;
+
+  i:=Self.FieldIndex[FieldName];
+
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  result := false;
+  if not EOF then
+  begin
+    Inc(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  result := false;
+  if not BOF then
+  begin
+    Dec(fRow);
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    result := true;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  result := false;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    result := true;
+  end;
+end;
+
+
+end.
+
Index: /oup/releases/0.21a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.21a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.21a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.21a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.21a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,986 @@
+UNIT Unit10_leveldb;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ComCtrls, StdCtrls;
+
+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 SQLiteTable3, 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,mem:TMemoryStream;
+
+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;
+
+    DB:=TSQLiteDatabase.Create(FileName);
+    DB.ExecSQL('PRAGMA synchronous = 0;');
+    DB.ExecSQL('PRAGMA temp_store = 2;');
+    DB.ExecSQL('DROP TABLE globals;');
+    DB.ExecSQL('DROP TABLE linkmap;');
+    DB.ExecSQL('DROP TABLE rawmap;');
+    DB.ExecSQL('DROP TABLE datfiles;');
+    DB.ExecSQL('DROP TABLE extlist;');
+    DB.ExecSQL('VACUUM;');
+
+    DoStep('Creating tables');
+    progress.Position:=0;
+    lbl_progress.Caption:='';
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+    Application.ProcessMessages;
+
+    DB.ExecSQL('CREATE TABLE globals  (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR (20), value VARCHAR (50) );');
+    DB.ExecSQL('CREATE TABLE linkmap  (id INTEGER PRIMARY KEY AUTOINCREMENT, src_id INTEGER, src_link_offset INTEGER, target_id INTEGER );');
+    DB.ExecSQL('CREATE TABLE rawmap   (id INTEGER PRIMARY KEY AUTOINCREMENT, src_id INTEGER, src_link_offset INTEGER, data BLOB );');
+    DB.ExecSQL('CREATE TABLE datfiles (id INTEGER PRIMARY KEY, extension VARCHAR(4), name VARCHAR(128), contenttype INTEGER, data BLOB );');
+    DB.ExecSQL('CREATE TABLE extlist  (id INTEGER PRIMARY KEY AUTOINCREMENT, ext VARCHAR(4), ident VARCHAR(16) );');
+
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("dbversion","'+dbversion+'");');
+    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);
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("ident","'+temps+'");');
+    data:=LoadDatFile(0);
+    i:=data[7];
+    i:=i DIV 2;
+    DB.ExecSQL('INSERT INTO globals (name,value) VALUES ("lvl","'+IntToStr(i)+'");');
+
+    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];
+      DB.ExecSQL('INSERT INTO extlist (ext,ident) VALUES ("'+temps2+'","'+temps+'");');
+      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;
+
+    FOR i:=0 TO dat_header.Files-1 DO BEGIN
+      DB.ExecSQL('INSERT INTO datfiles (id,extension,name,contenttype) VALUES ('+IntToStr(i)+',"'+dat_files[i].Extension+'","'+dat_files[i].Name+'","'+IntToHex(dat_files[i].FileType,8)+'");');
+      IF (dat_files[i].FileType AND $02)=0 THEN BEGIN
+        dat_stream.Seek(dat_files[i].DatAddr,soFromBeginning);
+        mem:=TMemoryStream.Create;
+        mem.CopyFrom(dat_stream,dat_files[i].Size);
+        mem.Seek(0,soFromBeginning);
+        DB.UpdateBlob('UPDATE datfiles SET data = ? WHERE id='+IntToStr(i)+';',mem);
+        HandleFile(dat_files[i].Extension,i,True);
+        mem.Free;
+      END;
+      IF ( (i MOD 50)=0 ) AND (i>=100) THEN
+        lbl_estimation.Caption:='Estimated finishing time: '+TimeToStr((Time-begintime)/i*dat_header.Files+begintime);
+      IF (i MOD 5)=0 THEN BEGIN
+        progress.Position:=i;
+        lbl_progress.Caption:='Files done: '+IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        Application.ProcessMessages;
+      END;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    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;
+    DB.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)';
+    IF MessageBox(Self.Handle, PChar('Delete the unfinished DB-file?'), PChar('Delete file?'), MB_YESNO)=IDYES THEN BEGIN
+      DB.Free;
+      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(offset,size:LongWord; target:Pointer);
+  BEGIN
+    mem.Seek(offset,soFromBeginning);
+    mem.Read(target^,size);
+  END;
+
+PROCEDURE InsertDatLinkToDB(fileid:LongWord; offset:LongWord);
+  VAR
+    link:LongWord;
+  BEGIN
+    LoadFilePart(offset,4,@link);
+    IF link=0 THEN
+      link:=$FFFFFFFF
+    ELSE
+      link:=link DIV 256;
+    DB.ExecSQL('INSERT INTO linkmap (src_id,src_link_offset,target_id) VALUES ('+IntToStr(fileid)+','+IntToStr(offset)+','+IntToStr(link)+');');
+  END;
+
+PROCEDURE InsertRawFileToDB(fileid:LongWord; src_offset,raw_addr,size:LongWord);
+  VAR
+    localmem:TMemoryStream;
+  BEGIN
+    localmem:=TMemoryStream.Create;
+    filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+    filestream.Seek(raw_addr,soFromBeginning);
+    localmem.CopyFrom(filestream,size);
+    filestream.Free;
+    DB.ExecSQL('INSERT INTO rawmap (src_id,src_link_offset) VALUES ('+IntToStr(fileid)+','+IntToStr(src_offset)+');');
+    DB.UpdateBlob('UPDATE rawmap SET data = ? WHERE src_id='+IntToStr(fileid),localmem);
+    localmem.Free;
+  END;
+
+
+
+PROCEDURE AGDB(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart($1C,4,@links);
+      links:=links*2;
+      FOR i:=0 TO links-1 DO BEGIN
+        LoadFilePart($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($0C,4,@link);
+      LoadFilePart($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($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($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($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($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($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($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($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($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($08,4,@datasize);
+      LoadFilePart($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($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($40,4,@datasize);
+      LoadFilePart($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:LongWord;
+    data:Tdata;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      LoadFilePart($18,4,@baselink);
+      LoadFilePart($1C,4,@links);
+      IF links>0 THEN BEGIN
+        FOR i:=0 TO links-1 DO BEGIN
+          LoadFilePart($20+i*4,4,@link);
+          SetLength(data,1024);
+          LoadRawFile(fileid,baselink+link,1024,@data[0]);
+          FOR j:=0 TO 1024 DO BEGIN
+            IF (data[j]=$00) OR (j=1024) THEN BEGIN
+              IF j<1024 THEN
+                InsertRawFileToDB(fileid,$20+i*4,baselink+link,j)
+              ELSE
+                ShowMessage('Error: Didn''t find message-end-marker...');
+              Break;
+            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($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($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;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      FOR i:=0 TO 11 DO BEGIN
+        LoadFilePart($0C+i*4,4,@link);
+        InsertRawFileToDB(fileid,$0C+i*4,link,1{????????????????????????????????});
+      END;
+      LoadFilePart($13C,4,@link);
+      InsertRawFileToDB(fileid,$13C,link,1{????????????????????????????????});
+    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($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($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($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($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($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($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($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($8C,SizeOf(x),@x);
+      LoadFilePart($8E,SizeOf(y),@y);
+      LoadFilePart($90,SizeOf(storetype),@storetype);
+      LoadFilePart($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($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.21a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.21a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.21a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,223 @@
+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 = 371
+      Width = 187
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        Width = 183
+        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 = 0
+        OnClick = combo_extensionClick
+      end
+    end
+    object list: TListBox
+      Left = 2
+      Top = 15
+      Width = 187
+      Height = 356
+      Align = alClient
+      ItemHeight = 13
+      MultiSelect = True
+      TabOrder = 0
+    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.21a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.21a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit11_extractor.pas	(revision 8)
@@ -0,0 +1,208 @@
+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;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    list: TListBox;
+    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;
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE FormActivate(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE Extract(Sender: TObject);
+  PRIVATE
+  PUBLIC
+    PROCEDURE Recreatelist;
+  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.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm11.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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.21a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.21a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.21a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -0,0 +1,17 @@
+object Form12: TForm12
+  Left = 0
+  Top = 0
+  BorderStyle = bsToolWindow
+  Caption = 'Value Edit'
+  ClientHeight = 298
+  ClientWidth = 428
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  PixelsPerInch = 96
+  TextHeight = 13
+end
Index: /oup/releases/0.21a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.21a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,24 @@
+unit Unit12_ValueEdit;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs;
+
+type
+  TForm12 = class(TForm)
+  private
+    { Private declarations }
+  public
+    { Public declarations }
+  end;
+
+var
+  Form12: TForm12;
+
+implementation
+
+{$R *.dfm}
+
+end.
Index: /oup/releases/0.21a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.21a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.21a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,167 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  AutoScroll = False
+  Caption = 'Form1'
+  ClientHeight = 544
+  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
+  OnClose = FormClose
+  OnCreate = FormCreate
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object statbar: TStatusBar
+    Left = 0
+    Top = 527
+    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 = 507
+    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.21a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.21a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,434 @@
+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 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 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.21a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.21a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,456 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math, SQLiteTable3,
+      Unit3_data, Unit4_Exporters;
+
+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 LoadDatInfos(filename:String):Boolean;
+PROCEDURE OpenDatabase(FileName:String);
+
+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
+
+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
+    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 GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringList;
+  VAR
+    i:LongWord;
+    where:String;
+    Tbl:TSQLiteTable;
+  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(pattern,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)=0)';
+      END;
+      IF Length(where)>0 THEN where:=' WHERE '+where;
+      Tbl:=DB.GetTable('SELECT id,name,extension FROM datfiles'+where+' ORDER BY id ASC;');
+      IF Tbl.Count>0 THEN BEGIN
+        SetLength(Result,Tbl.Count);
+        i:=0;
+        REPEAT
+          Result[i]:=FormatNumber(Tbl.FieldAsInteger('id'),5,'0')+'-'+Tbl.FieldAsString('name')+'.'+Tbl.FieldAsString('extension');
+          Inc(i);
+          Tbl.Next;
+        UNTIL Tbl.EOF;
+      END;
+    END;
+  END;
+
+FUNCTION GetExtensionsList:TStringList;
+  VAR
+    i:LongWord;
+    Tbl:TSQLiteTable;
+  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
+      Tbl:=DB.GetTable('SELECT extension,count(extension) AS x FROM datfiles GROUP BY extension ORDER BY extension ASC;');
+      IF Tbl.Count>0 THEN BEGIN
+        SetLength(Result,Tbl.Count);
+        i:=0;
+        REPEAT
+          Result[i]:=Tbl.FieldAsString('extension')+' ('+IntToStr(Tbl.FieldAsInteger('x'))+')';
+          Inc(i);
+          Tbl.Next;
+        UNTIL Tbl.EOF;
+      END;
+    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;
+    Tbl:TSQLiteTable;
+    mem:TMemoryStream;
+  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
+      Tbl:=DB.GetTable('SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';');
+      IF Tbl.Count>0 THEN BEGIN
+        mem:=Tbl.FieldAsBlob('data');
+        SetLength(Result,mem.Size);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(Result[0],mem.Size);
+        mem.Free;
+      END;
+    END;
+  END;
+PROCEDURE UpdateDatFile(fileid:LongWord; data:Tdata);
+  VAR
+    dat_file:TFileStream;
+    Tbl:TSQLiteTable;
+  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;
+    Tbl:TSQLiteTable;
+    mem:TMemoryStream;
+  BEGIN
+    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
+      Tbl:=DB.GetTable('SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';');
+      IF Tbl.Count>0 THEN BEGIN
+        Result:=True;
+        mem:=Tbl.FieldAsBlob('data');
+        mem.Seek(offset,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+    END;
+  END;
+FUNCTION UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer):Boolean;
+  VAR
+    dat_file:TFileStream;
+    Tbl:TSQLiteTable;
+  BEGIN
+    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;
+    Tbl:TSQLiteTable;
+    mem:TMemoryStream;
+  BEGIN
+    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
+      Tbl:=DB.GetTable('SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(datlinkoffset)+');');
+      IF Tbl.Count>0 THEN BEGIN
+        Result:=True;
+        mem:=Tbl.FieldAsBlob('data');
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+    END;
+  END;
+FUNCTION UpdateRawFile(fileid,datlinkoffset,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    raw_addr:LongWord;
+  BEGIN
+    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;
+    data:Tdata;
+    temps:String;
+    Tbl: TSQLiteTable;
+  BEGIN
+    IF NOT FileExists(FileName) THEN BEGIN
+      ShowMessage('File doesn''t exist!!!');
+      Exit;
+    END;
+    DB:=TSQLiteDatabase.Create(FileName);
+    Tbl:=DB.GetTable('SELECT name,value FROM globals ORDER BY name ASC');
+    REPEAT
+      IF Tbl.FieldAsString('name')='dbversion' THEN BEGIN
+        IF Tbl.FieldAsString('value')<>DBversion THEN BEGIN
+          ShowMessage('Database-file '+CrLf+'"'+FileName+'"'+CrLf+'has wrong version. (Required: '+DBversion+'; found: '+Tbl.FieldAsString('value')+')');
+          Exit;
+        END;
+      END;
+      IF Tbl.FieldAsString('name')='lvl' THEN BEGIN
+        database_level:=StrToInt(Tbl.FieldAsString('value'));
+      END;
+      IF Tbl.FieldAsString('name')='ident' THEN BEGIN
+        temps:=Tbl.FieldAsString('value');
+        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;
+      Tbl.Next;
+    UNTIL Tbl.EOF;
+    Tbl.Free;
+    opened_state:=opened_db;
+  END;
+
+
+
+
+END.
Index: /oup/releases/0.21a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.21a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,103 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes, SQLiteTable3;
+
+VAR
+  DB: TSQLiteDatabase;
+
+CONST
+  version:String='v0.21a';
+  dbversion:String='0.1';
+  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;
+  Tfiles=Array OF PACKED RECORD
+    FileName:String;
+    Extension:String[4];
+    Name:String;
+    Size:LongWord;
+    FileType:LongWord;
+    DatAddr:LongWord;
+    opened:Boolean;
+  END;
+
+  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.21a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.21a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,196 @@
+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
+      _fileid:LongWord;
+      level:LongWord;
+      Flag:LongWord;
+      FormatTag:Word;
+      ChanNo:Word;
+      SampleRate:LongWord;
+      BytesPSec:LongWord;
+      BPSample:LongWord;
+      BitsPS:LongWord;
+      Unknown:Array[1..7] OF LongWord;
+      Unknown2:Word;
+      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.21a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.21a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.21a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,177 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 319
+  Height = 181
+  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 = 154
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_preview: TPanel
+    Left = 159
+    Top = 0
+    Width = 152
+    Height = 154
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object img: TImage
+      Left = 0
+      Top = 20
+      Width = 152
+      Height = 134
+      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 = 152
+      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 = 154
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 129
+      Align = alClient
+      ItemHeight = 13
+      PopupMenu = popup
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 129
+      Width = 150
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        Width = 145
+        Height = 21
+        Style = csDropDownList
+        DropDownCount = 12
+        Font.Charset = DEFAULT_CHARSET
+        Font.Color = clWindowText
+        Font.Height = -11
+        Font.Name = 'Tahoma'
+        Font.Style = []
+        ItemHeight = 0
+        ParentFont = False
+        Sorted = True
+        TabOrder = 0
+        OnClick = combo_extensionClick
+      end
+    end
+  end
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 144
+    Top = 24
+  end
+  object popup: TPopupMenu
+    AutoHotkeys = maManual
+    Left = 48
+    Top = 56
+    object popup_extractdat: TMenuItem
+      Caption = 'Extract .dat-file'
+      Enabled = False
+    end
+    object popup_extractdatraw: TMenuItem
+      Caption = 'Extract .dat-file and corresponding .raw-data'
+      Enabled = False
+    end
+    object popup_extractdatrawconvert: TMenuItem
+      Caption = 
+        'Extract .dat-file and corresponding .raw-data and convert if pos' +
+        'sible'
+      Enabled = False
+    end
+  end
+end
Index: /oup/releases/0.21a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.21a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,257 @@
+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;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    Splitter1: TSplitter;
+    lbl_notpossible: TLabel;
+    popup: TPopupMenu;
+    popup_extractdat: TMenuItem;
+    popup_extractdatraw: TMenuItem;
+    popup_extractdatrawconvert: TMenuItem;
+    procedure FormActivate(Sender: TObject);
+    PROCEDURE Recreatelist;
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE PreviewTXAN;
+    PROCEDURE PreviewTXMB;
+    PROCEDURE PreviewTXMP;
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    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.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.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+
+PROCEDURE TForm5.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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 '+dat_files[_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 '+dat_files[_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 '+dat_files[_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.21a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.21a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -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.21a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.21a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.21a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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.21a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.21a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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.21a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.21a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.21a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,207 @@
+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 = 300
+      Width = 483
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 50
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 483
+      Height = 300
+      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
+      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 = 309
+      Width = 483
+      Height = 114
+      Align = alClient
+      DefaultColWidth = 92
+      DefaultRowHeight = 18
+      FixedCols = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      TabOrder = 1
+      OnClick = structsClick
+    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 = 315
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 315
+      Width = 150
+      Height = 44
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object lbl_filter: TLabel
+        Left = 2
+        Top = 4
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = '&Filter by extension:'
+        FocusControl = combo_extension
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 20
+        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 = 0
+        OnClick = combo_extensionClick
+      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
+end
Index: /oup/releases/0.21a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.21a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,410 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls,
+  Unit3_data, Unit2_functions, Unit9_data_structures, Unit4_exporters;
+
+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;
+{    PROCEDURE structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
+    PROCEDURE structsSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
+    PROCEDURE structsKeyPress(Sender: TObject; var Key: Char);
+}    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);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    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 listClick(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE Recreatelist;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  fileid:LongWord;
+
+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.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.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    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;
+    Self.panel_dataResize(Self);
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+dat_files[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.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(dat_files[fileid].Extension));
+    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;
+  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(dat_files[fileid].extension)].entries[structs.Row-1].offset;
+      length:=GetTypeDataLength(structure_infos[GetStructureInfoId(dat_files[fileid].extension)].entries[structs.Row-1].datatype);
+      hex.SelStart:=offset;
+      hex.SelEnd:=offset+length-1;
+{      IF structs.Cells[structs.Col,0]='Value' THEN
+        IF structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype<=10 THEN
+          structs.Options:=structs.Options+[goEditing]
+      ELSE
+        structs.Options:=structs.Options-[goEditing];
+}    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;
+  END;
+
+PROCEDURE TForm8.hexChange(Sender: TObject);
+  BEGIN
+    IF hex.DataSize>0 THEN
+      WriteStructureInfos(GetStructureInfoId(dat_files[fileid].Extension));
+  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(dat_files[fileid].Extension)>=0 THEN BEGIN
+        WITH structure_infos[GetStructureInfoId(dat_files[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;
+    END;
+  END;
+
+PROCEDURE TForm8.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm8.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    saved.DefaultExt:=dat_files[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 (*.'+dat_files[fileid].Extension+')|*.'+dat_files[fileid].Extension+'|All files|*.*';
+    IF opend.Execute THEN BEGIN
+      fs:=TFileStream.Create(opend.FileName,fmOpenRead);
+      IF fs.Size<>dat_files[fileid].size 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(dat_files[fileid].size)+CrLf+
+                    'Size of chosen file: '+FormatFileSize(fs.Size));
+      END ELSE BEGIN
+        SetLength(data,fs.Size);
+        fs.Read(data[0],fs.Size);
+        fs.Free;
+        fs:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+        fs.Seek(dat_files[fileid].dataddr,soFromBeginning);
+        fs.Write(data[0],Length(data));  
+      END;
+      fs.Free;
+      listClick(Self);
+    END;
+  END;
+
+PROCEDURE TForm8.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+{
+PROCEDURE TForm8.structsKeyPress(Sender: TObject; VAR Key: Char);
+  VAR
+    dt:Byte;
+  BEGIN
+    IF structs.EditorMode THEN BEGIN
+      dt:=structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype;
+      CASE dt OF
+        1..4: BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'9']) THEN Key:=#0;
+              END;
+        5..8: BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'9','A'..'F','a'..'f']) THEN Key:=#0;
+                IF Key IN ['a'..'f'] THEN Key:=UpCase(Key);
+                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=2*(dt-4) ) THEN Key:=#0;
+              END;
+        9:    BEGIN
+                IF (Key IN ['.']) AND (Pos('.',structs.Cells[structs.Col,structs.Row])>0) THEN Key:=#0;
+                IF NOT (Key IN [#8,#13,#27,'0'..'9','.','-']) THEN Key:=#0;
+              END;
+        10:   BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'1']) THEN Key:=#0;
+                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=8 ) THEN Key:=#0;
+              END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.structsSetEditText(Sender: TObject; ACol, ARow: Integer; CONST Value: string);
+  BEGIN
+    IF NOT TWrapGrid(Sender).EditorMode THEN
+      ShowMessage('['+IntToStr(ACol)+'|'+IntToStr(ARow)+']='+Value);
+  END;
+
+PROCEDURE TForm8.structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
+  BEGIN
+    IF structs.EditorMode THEN
+      ShowMessage('EditorMode - '+Value)
+    ELSE
+      ShowMessage('NOT EditorMode - '+Value);
+  END;
+}
+END.
Index: /oup/releases/0.21a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.21a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.21a/src/Unit9_data_structures.pas	(revision 8)
@@ -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.
Index: /oup/releases/0.22a/_changelog.txt
===================================================================
--- /oup/releases/0.22a/_changelog.txt	(revision 8)
+++ /oup/releases/0.22a/_changelog.txt	(revision 8)
@@ -0,0 +1,52 @@
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.22a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.22a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.22a/src/OniUnPacker.bdsproj	(revision 8)
@@ -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.22a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.22a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.22a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,28 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.530.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.540.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.10.28 00:20:57.420.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.pas</Transaction>
+    <Transaction>2005.10.28 00:20:57.440.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.dfm</Transaction>
+    <Transaction>2005.12.18 11:32:06.823.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.pas</Transaction>
+    <Transaction>2005.12.18 11:32:06.833.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.dfm</Transaction>
+    <Transaction>2005.12.22 16:36:15.685.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions_ABS.pas</Transaction>
+    <Transaction>2005.12.22 16:39:50.444.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.pas</Transaction>
+    <Transaction>2005.12.22 16:39:50.444.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.dfm</Transaction>
+    <Transaction>2005.12.24 01:01:39.626.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.12.24 01:01:39.656.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.12.24 01:01:49.189.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions_ABS.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions.pas</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.22a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.22a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.22a/src/OniUnPacker.cfg	(revision 8)
@@ -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.22a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.22a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.22a/src/OniUnPacker.dpr	(revision 8)
@@ -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.22a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.22a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.22a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.22a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.22a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,1025 @@
+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, 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, data BLOB BlobCompressionAlgorithm None );';
+    Query.ExecSQL;
+    Query.SQL.Text:='CREATE TABLE datfiles  ( id INTEGER PRIMARY KEY, extension CHAR(4), name STRING(128), contenttype 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, 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,data) VALUES ('+IntToStr(i)+',"'+dat_files[i].Extension+'","'+dat_files[i].Name+'","'+IntToHex(dat_files[i].FileType,8)+'",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) VALUES ('+IntToStr(i)+',"'+dat_files[i].Extension+'","'+dat_files[i].Name+'","'+IntToHex(dat_files[i].FileType,8)+'");';
+        Query.ExecSQL;
+      END;
+      IF ( (i MOD 100)=0 ) AND (i>0) THEN BEGIN
+        Database.Commit(False);
+        Database.StartTransaction;
+      END;
+      IF ( (i MOD 50)=0 ) AND (i>=100) THEN
+        lbl_estimation.Caption:='Estimated finishing time: '+TimeToStr((Time-begintime)/i*dat_header.Files+begintime);
+      IF (i MOD 5)=0 THEN BEGIN
+        progress.Position:=i;
+        lbl_progress.Caption:='Files done: '+IntToStr(i)+'/'+IntToStr(dat_header.Files);
+        Application.ProcessMessages;
+      END;
+      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;
+  BEGIN
+    filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+    filestream.Seek(raw_addr,soFromBeginning);
+    mimecoder:=TStringFormat_MIME64.Create;
+    localmem:=TMemoryStream.Create;
+    localmem.CopyFrom(filestream,size);
+    Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,data) VALUES ('+IntToStr(fileid)+','+IntToStr(src_offset)+',MimeToBin("'+MimeCoder.StrTo(localmem.Memory, localmem.Size)+'") );';
+    Query.ExecSQL;
+    localmem.Free;
+    mimecoder.Free;
+    filestream.Free;
+  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;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+    {
+    $0C
+    }
+      FOR i:=0 TO 11 DO BEGIN
+        LoadFilePart(fileid,$0C+i*4,4,@link);
+        InsertRawFileToDB(fileid,$0C+i*4,link,1(*????????????????????????????????*));
+      END;
+      LoadFilePart(fileid,$13C,4,@link);
+      InsertRawFileToDB(fileid,$13C,link,1(*????????????????????????????????*));
+    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.22a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.22a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.22a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,223 @@
+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 = 371
+      Width = 187
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        Width = 183
+        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 = 0
+        OnClick = combo_extensionClick
+      end
+    end
+    object list: TListBox
+      Left = 2
+      Top = 15
+      Width = 187
+      Height = 356
+      Align = alClient
+      ItemHeight = 13
+      MultiSelect = True
+      TabOrder = 0
+    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.22a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.22a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit11_extractor.pas	(revision 8)
@@ -0,0 +1,208 @@
+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;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    list: TListBox;
+    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;
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE FormActivate(Sender: TObject);
+    PROCEDURE FormClose(Sender: TObject; var Action: TCloseAction);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE Extract(Sender: TObject);
+  PRIVATE
+  PUBLIC
+    PROCEDURE Recreatelist;
+  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.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm11.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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.22a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.22a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.22a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -0,0 +1,19 @@
+object Form12: TForm12
+  Left = 0
+  Top = 0
+  BorderStyle = bsNone
+  BorderWidth = 1
+  Caption = 'Value Edit'
+  ClientHeight = 318
+  ClientWidth = 432
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  PixelsPerInch = 96
+  TextHeight = 13
+end
Index: /oup/releases/0.22a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.22a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,20 @@
+UNIT Unit12_ValueEdit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs;
+TYPE
+  TForm12 = Class(TForm)
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form12: TForm12;
+
+
+IMPLEMENTATION
+USES Unit1_main, Unit8_binedit;
+{$R *.dfm}
+
+END.
Index: /oup/releases/0.22a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.22a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.22a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,167 @@
+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
+  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.22a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.22a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit1_main.pas	(revision 8)
@@ -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.22a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.22a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,522 @@
+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 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
+    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 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(pattern,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;
+    data:Tdata;
+    temps:String;
+    //Tbl: TSQLiteTable;
+  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+')');
+          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.22a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.22a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,102 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.22a';
+  dbversion:String='0.1';
+  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.22a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.22a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,196 @@
+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
+      _fileid:LongWord;
+      level:LongWord;
+      Flag:LongWord;
+      FormatTag:Word;
+      ChanNo:Word;
+      SampleRate:LongWord;
+      BytesPSec:LongWord;
+      BPSample:LongWord;
+      BitsPS:LongWord;
+      Unknown:Array[1..7] OF LongWord;
+      Unknown2:Word;
+      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.22a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.22a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.22a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,177 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Width = 319
+  Height = 181
+  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 = 154
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_preview: TPanel
+    Left = 159
+    Top = 0
+    Width = 152
+    Height = 154
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    object img: TImage
+      Left = 0
+      Top = 20
+      Width = 152
+      Height = 134
+      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 = 152
+      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 = 154
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 129
+      Align = alClient
+      ItemHeight = 13
+      PopupMenu = popup
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 129
+      Width = 150
+      Height = 25
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 2
+        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 = 0
+        OnClick = combo_extensionClick
+      end
+    end
+  end
+  object timer: TTimer
+    Enabled = False
+    OnTimer = timerTimer
+    Left = 144
+    Top = 24
+  end
+  object popup: TPopupMenu
+    AutoHotkeys = maManual
+    Left = 48
+    Top = 56
+    object popup_extractdat: TMenuItem
+      Caption = 'Extract .dat-file'
+      Enabled = False
+    end
+    object popup_extractdatraw: TMenuItem
+      Caption = 'Extract .dat-file and corresponding .raw-data'
+      Enabled = False
+    end
+    object popup_extractdatrawconvert: TMenuItem
+      Caption = 
+        'Extract .dat-file and corresponding .raw-data and convert if pos' +
+        'sible'
+      Enabled = False
+    end
+  end
+end
Index: /oup/releases/0.22a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.22a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,257 @@
+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;
+    panel_files: TPanel;
+    list: TListBox;
+    panel_extension: TPanel;
+    combo_extension: TComboBox;
+    Splitter1: TSplitter;
+    lbl_notpossible: TLabel;
+    popup: TPopupMenu;
+    popup_extractdat: TMenuItem;
+    popup_extractdatraw: TMenuItem;
+    popup_extractdatrawconvert: TMenuItem;
+    procedure FormActivate(Sender: TObject);
+    PROCEDURE Recreatelist;
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE PreviewTXAN;
+    PROCEDURE PreviewTXMB;
+    PROCEDURE PreviewTXMP;
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    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.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.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+
+PROCEDURE TForm5.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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.22a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.22a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -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.22a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.22a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.22a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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.22a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.22a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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.22a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.22a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.22a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,231 @@
+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 = 185
+      Width = 483
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+    end
+    object Splitter3: TSplitter
+      Left = 0
+      Top = 349
+      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 = 185
+      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
+      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 = 357
+      Width = 483
+      Height = 66
+      Align = alBottom
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      TabOrder = 1
+      OnClick = structsClick
+    end
+    object value_viewer: TWrapGrid
+      Left = 0
+      Top = 194
+      Width = 483
+      Height = 155
+      Align = alClient
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      TabOrder = 2
+    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 = 315
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 315
+      Width = 150
+      Height = 44
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 1
+      OnResize = panel_extensionResize
+      object lbl_filter: TLabel
+        Left = 2
+        Top = 4
+        Width = 100
+        Height = 17
+        AutoSize = False
+        Caption = '&Filter by extension:'
+        FocusControl = combo_extension
+      end
+      object combo_extension: TComboBox
+        Left = 2
+        Top = 20
+        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 = 0
+        OnClick = combo_extensionClick
+      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
+end
Index: /oup/releases/0.22a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.22a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,509 @@
+UNIT Unit8_binedit;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Wrapgrid, StdCtrls, Grids, StrUtils, MPHexEditor, ExtCtrls,
+  Unit3_data, Unit2_functions, Unit9_data_structures, Unit4_exporters;
+
+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;
+{    PROCEDURE structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
+    PROCEDURE structsSetEditText(Sender: TObject; ACol, ARow: Integer; const Value: string);
+    PROCEDURE structsKeyPress(Sender: TObject; var Key: Char);
+}    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);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    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 listClick(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE Recreatelist;
+    PROCEDURE ClearValues;
+    PROCEDURE WriteValues;
+  PRIVATE
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+VAR
+  fileid:LongWord;
+
+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;
+  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) THEN
+          value_viewer.Cells[1,i]:=IntToStr(hex.Data[hex.SelStart])
+        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) THEN
+          value_viewer.Cells[1,i]:=IntToStr( hex.Data[hex.SelStart]+hex.Data[hex.SelStart+1]*256 )
+        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) THEN
+          value_viewer.Cells[1,i]:=IntToStr( 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 )
+        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) 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 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.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.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    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;
+    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.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));
+    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;
+  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;
+{      IF structs.Cells[structs.Col,0]='Value' THEN
+        IF structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype<=10 THEN
+          structs.Options:=structs.Options+[goEditing]
+      ELSE
+        structs.Options:=structs.Options-[goEditing];
+}    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.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm8.combo_extensionClick(Sender: TObject);
+  VAR
+    Extension:String[4];
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    list.Items.Clear;
+    IF Extension='_All' THEN
+      files:=GetFilesList('','',True)
+    ELSE
+      files:=GetFilesList(extension,'',True);
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+  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
+{        SetLength(data,fs.Size);
+        fs.Read(data[0],fs.Size);
+        fs.Free;
+        fs:=TFileStream.Create(dat_filename,fmOpenReadWrite);
+        fs.Seek(dat_files[fileid].dataddr,soFromBeginning);
+        fs.Write(data[0],Length(data));
+}      END;
+      fs.Free;
+      listClick(Self);
+    END;
+  END;
+
+PROCEDURE TForm8.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+{
+PROCEDURE TForm8.structsKeyPress(Sender: TObject; VAR Key: Char);
+  VAR
+    dt:Byte;
+  BEGIN
+    IF structs.EditorMode THEN BEGIN
+      dt:=structure_infos[GetStructureInfoId(dat_files[fileid].Extension)].entries[structs.Row-1].datatype;
+      CASE dt OF
+        1..4: BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'9']) THEN Key:=#0;
+              END;
+        5..8: BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'9','A'..'F','a'..'f']) THEN Key:=#0;
+                IF Key IN ['a'..'f'] THEN Key:=UpCase(Key);
+                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=2*(dt-4) ) THEN Key:=#0;
+              END;
+        9:    BEGIN
+                IF (Key IN ['.']) AND (Pos('.',structs.Cells[structs.Col,structs.Row])>0) THEN Key:=#0;
+                IF NOT (Key IN [#8,#13,#27,'0'..'9','.','-']) THEN Key:=#0;
+              END;
+        10:   BEGIN
+                IF NOT (Key IN [#8,#13,#27,'0'..'1']) THEN Key:=#0;
+                IF NOT (Key IN [#8,#13,#27]) AND ( Length(structs.Cells[structs.Col,structs.Row])>=8 ) THEN Key:=#0;
+              END;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.structsSetEditText(Sender: TObject; ACol, ARow: Integer; CONST Value: string);
+  BEGIN
+    IF NOT TWrapGrid(Sender).EditorMode THEN
+      ShowMessage('['+IntToStr(ACol)+'|'+IntToStr(ARow)+']='+Value);
+  END;
+
+PROCEDURE TForm8.structsGetEditText(Sender: TObject; ACol, ARow: Integer; var Value: string);
+  BEGIN
+    IF structs.EditorMode THEN
+      ShowMessage('EditorMode - '+Value)
+    ELSE
+      ShowMessage('NOT EditorMode - '+Value);
+  END;
+}
+END.
Index: /oup/releases/0.22a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.22a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.22a/src/Unit9_data_structures.pas	(revision 8)
@@ -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.
Index: /oup/releases/0.23a/_changelog.txt
===================================================================
--- /oup/releases/0.23a/_changelog.txt	(revision 8)
+++ /oup/releases/0.23a/_changelog.txt	(revision 8)
@@ -0,0 +1,58 @@
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.23a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.23a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.23a/src/OniUnPacker.bdsproj	(revision 8)
@@ -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/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.23a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.23a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,28 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.530.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.540.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.10.28 00:20:57.420.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.pas</Transaction>
+    <Transaction>2005.10.28 00:20:57.440.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.dfm</Transaction>
+    <Transaction>2005.12.18 11:32:06.823.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.pas</Transaction>
+    <Transaction>2005.12.18 11:32:06.833.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.dfm</Transaction>
+    <Transaction>2005.12.22 16:36:15.685.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions_ABS.pas</Transaction>
+    <Transaction>2005.12.22 16:39:50.444.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.pas</Transaction>
+    <Transaction>2005.12.22 16:39:50.444.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.dfm</Transaction>
+    <Transaction>2005.12.24 01:01:39.626.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.12.24 01:01:39.656.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.12.24 01:01:49.189.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions_ABS.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions.pas</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.23a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.23a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.23a/src/OniUnPacker.cfg	(revision 8)
@@ -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/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.23a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.23a/src/OniUnPacker.dpr	(revision 8)
@@ -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/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.23a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.23a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.23a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit10_leveldb.pas	(revision 8)
@@ -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/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.23a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.23a/src/Unit11_extractor.dfm	(revision 8)
@@ -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/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.23a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit11_extractor.pas	(revision 8)
@@ -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/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.23a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.23a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.23a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -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/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.23a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.23a/src/Unit1_main.dfm	(revision 8)
@@ -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/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.23a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit1_main.pas	(revision 8)
@@ -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/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.23a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit2_functions.pas	(revision 8)
@@ -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/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.23a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit3_data.pas	(revision 8)
@@ -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/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.23a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit4_Exporters.pas	(revision 8)
@@ -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/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.23a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.23a/src/Unit5_preview.dfm	(revision 8)
@@ -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/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.23a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit5_preview.pas	(revision 8)
@@ -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/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.23a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -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/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.23a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.23a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.23a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.23a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.23a/src/Unit8_binedit.dfm	(revision 8)
@@ -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/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.23a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit8_binedit.pas	(revision 8)
@@ -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/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.23a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.23a/src/Unit9_data_structures.pas	(revision 8)
@@ -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.
Index: /oup/releases/0.24a/_changelog.txt
===================================================================
--- /oup/releases/0.24a/_changelog.txt	(revision 8)
+++ /oup/releases/0.24a/_changelog.txt	(revision 8)
@@ -0,0 +1,62 @@
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.24a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.24a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.24a/src/OniUnPacker.bdsproj	(revision 8)
@@ -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.24a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.24a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.24a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,28 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.530.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.540.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.10.28 00:20:57.420.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.pas</Transaction>
+    <Transaction>2005.10.28 00:20:57.440.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.dfm</Transaction>
+    <Transaction>2005.12.18 11:32:06.823.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.pas</Transaction>
+    <Transaction>2005.12.18 11:32:06.833.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.dfm</Transaction>
+    <Transaction>2005.12.22 16:36:15.685.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions_ABS.pas</Transaction>
+    <Transaction>2005.12.22 16:39:50.444.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.pas</Transaction>
+    <Transaction>2005.12.22 16:39:50.444.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.dfm</Transaction>
+    <Transaction>2005.12.24 01:01:39.626.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.12.24 01:01:39.656.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.12.24 01:01:49.189.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions_ABS.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions.pas</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.24a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.24a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.24a/src/OniUnPacker.cfg	(revision 8)
@@ -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.24a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.24a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.24a/src/OniUnPacker.dpr	(revision 8)
@@ -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.24a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.24a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.24a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.24a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.24a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,1090 @@
+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
+        LoadFilePart(fileid,$20+(links-1)*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,$1C,baselink,link+j);
+                Break;
+              END;
+            END ELSE
+              ShowMessage('Error: Didn''t find message-end-marker...');
+          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.24a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.24a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.24a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+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
+      MultiSelect = True
+      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.24a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.24a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit11_extractor.pas	(revision 8)
@@ -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.24a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.24a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.24a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -0,0 +1,156 @@
+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
+      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.24a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.24a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,103 @@
+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;
+    edit_new.BorderStyle:=bsSingle;
+    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.24a/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.24a/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.24a/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,325 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  Width = 650
+  Height = 667
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-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 = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = 600
+      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 = 374
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 322
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 337
+        Width = 146
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.24a/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.24a/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,754 @@
+UNIT Unit13_rawedit;
+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, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    check_zerobyte: TCheckBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    procedure list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    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_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+  dat_offset:LongWord;
+  fileid_opened,dat_offset_opened:LongWord;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    LoadRawFilebyIDOffset(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_zerobyteClick(Sender: TObject);
+  VAR
+    i:Byte;
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
+    list_offset.Enabled:=True;
+    IF GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,6)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,6));
+    LoadRaw(GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of 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;
+          UpdateRawFile(GetRawInfo(fileid_opened,dat_offset_opened),@data[0]);
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  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
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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.24a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.24a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.24a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,173 @@
+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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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.24a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.24a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,453 @@
+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, Unit13_rawedit;
+
+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;
+    menu_rawedit: TMenuItem;
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  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;
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.24a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.24a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,561 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data, 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,dat_offset,raw_addr,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; 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
+USES Unit4_Exporters, Unit9_data_structures;
+
+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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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:=Query.FieldByName('size').AsInteger;
+        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,dat_offset,raw_addr,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      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)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      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 LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+  VAR
+    i:Byte;
+    raw_info:TRawInfo;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      raw_info:=GetRawInfo(fileid,dat_offset);
+      LoadRawFile(fileid,dat_offset,raw_info.raw_addr,raw_info.raw_size,target);
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Result:=True;
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenReadWrite);
+      filestream.Seek(rawinfo.raw_addr,soFromBeginning);
+      filestream.Write(target^,rawinfo.raw_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.24a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.24a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,110 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.24a';
+  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;
+
+  TRawInfo=RECORD
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+  END;
+  TRawList=Array OF TRawInfo;
+
+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.24a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.24a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit4_Exporters.pas	(revision 8)
@@ -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,$44,rawpos,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.24a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.24a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.24a/src/Unit5_preview.dfm	(revision 8)
@@ -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.24a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.24a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit5_preview.pas	(revision 8)
@@ -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.24a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.24a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,400 @@
+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;
+  VAR
+    img_addr:LongWord;
+  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);
+    LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr);
+
+    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,img_addr,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.24a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.24a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.24a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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.24a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.24a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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.24a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.24a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.24a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,294 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  Width = 650
+  Height = 450
+  BorderIcons = [biSystemMenu, biMaximize]
+  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.24a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.24a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,707 @@
+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, Math;
+
+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 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_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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, Unit13_rawedit;
+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]);
+      11: Result:='0x'+IntToHex(GetRawInfo(fileid,offset).raw_addr,8);
+      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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        edit_filtername.Text:=IntToStr(GetRawInfo(fileid,offset).raw_size);
+        IF Form1.open_child('rawedit') THEN BEGIN
+          TForm13(Form1.ActiveMDIChild).LoadRaw(GetRawInfo(fileid,offset));
+        END;
+        {LOAD RAW-EDITOR}
+      END;
+    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.24a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.24a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.24a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,406 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, ABSMain, DB, ABSDecUtil, Unit3_data;
+
+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; 11: raw-addr; 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;
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+
+
+
+IMPLEMENTATION
+USES Unit2_functions;
+
+TYPE
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+VAR
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      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';
+      11: Result:='Raw-Address';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  VAR
+    i:LongWord;
+    raw_list:TRawList;
+  BEGIN
+    raw_list:=GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    FOR i:=0 TO High(raw_list) DO BEGIN
+      IF raw_list[i].src_offset=dat_offset THEN BEGIN
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Break;
+      END;
+    END;
+  END;
+
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+  VAR
+    i:LongWord;
+    Query:TABSQuery;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=1 TO Length(RawListHandlers) DO
+        IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN
+          IF RawListHandlers[i].needed THEN BEGIN
+            Result:=RawListHandlers[i].Handler(fileid);
+            Break;
+          END ELSE
+            Break;
+    END ELSE BEGIN
+      SetLength(Result,0);
+      Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i].src_id:=fileid;
+          Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger;
+          Result[i].raw_addr:=0;
+          Result[i].raw_size:=Query.FieldByName('size').AsInteger;
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$1C,4,@links);
+    links:=links*2;
+    SetLength(Result,links);
+    FOR i:=0 TO links-1 DO BEGIN
+      Result[i].src_offset:=$20+i*4;
+      LoadDatFilePart(fileid,$20+i*4,4,@link);
+      Result[i].raw_addr:=link;
+      Result[i].raw_size:=0{????????????????????????????????};
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$0C,4,@link);
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$40,4,@datasize);
+    LoadDatFilePart(fileid,$44,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$44;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,link:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    LoadDatFilePart(fileid,$18,4,@baselink);
+    LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      LoadDatFilePart(fileid,$20+(links-1)*4,4,@link);
+      SetLength(data,link+1024);
+      LoadRawFile(fileid,$1C,baselink,link+1024,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[link+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=link+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    LoadDatFilePart(fileid,$182,1,@tempb);
+    LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    LoadDatFilePart(fileid,$183,1,@tempb);
+    LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    LoadDatFilePart(fileid,$184,1,@tempb);
+    LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    LoadDatFilePart(fileid,$185,1,@tempb);
+    LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    Result[6].raw_size:=24;
+    {footstep}
+    LoadDatFilePart(fileid,$186,1,@tempb);
+    LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    LoadDatFilePart(fileid,$187,1,@tempb);
+    LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    LoadDatFilePart(fileid,$154,2,@tempw);
+    LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    LoadDatFilePart(fileid,$138,1,@templ);
+    LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      LoadRawFile(fileid,$34,link,$FFFF,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    LoadDatFilePart(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;
+    SetLength(Result,1);
+    Result[0].src_offset:=$9C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  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;
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+
+BEGIN
+  AddExtension('SUBT','Subtitles');
+  AddEntry('SUBT','ID',$00,4,'ID of this file');
+  AddEntry('SUBT','LevelID',$04,8,'ID of the level this file is in');
+  AddEntry('SUBT','Raw-Link',$18,11,'Address of the subtitle data in the .raw-file');
+  AddEntry('SUBT','Subtitle count',$1C,4,'Number of subtitles in this file');
+  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,11,'Address of the image data in the .raw-file');
+
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.25a/_changelog.txt
===================================================================
--- /oup/releases/0.25a/_changelog.txt	(revision 8)
+++ /oup/releases/0.25a/_changelog.txt	(revision 8)
@@ -0,0 +1,67 @@
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.25a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.25a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.25a/src/OniUnPacker.bdsproj	(revision 8)
@@ -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.25a/src/OniUnPacker.bdsproj.local
===================================================================
--- /oup/releases/0.25a/src/OniUnPacker.bdsproj.local	(revision 8)
+++ /oup/releases/0.25a/src/OniUnPacker.bdsproj.local	(revision 8)
@@ -0,0 +1,28 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<BorlandProject>
+	<Transactions>
+    <Transaction>2005.09.12 15:50:55.441.pas,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.pas</Transaction>
+    <Transaction>2005.09.12 15:50:55.451.dfm,C:\Dokumente und Einstellungen\Administrator\Eigene Dateien\Borland Studio Projects\Unit1.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1_main.dfm</Transaction>
+    <Transaction>2005.09.16 14:33:57.886.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit4_Exporters.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.217.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.pas</Transaction>
+    <Transaction>2005.09.19 21:00:33.227.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit5_preview.dfm</Transaction>
+    <Transaction>2005.09.20 21:51:14.061.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit6_imgfuncs.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.880.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.pas</Transaction>
+    <Transaction>2005.10.16 00:37:22.940.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit7_txmpreplace.dfm</Transaction>
+    <Transaction>2005.10.18 21:55:56.791.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.pas</Transaction>
+    <Transaction>2005.10.18 21:55:56.801.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit8_binedit.dfm</Transaction>
+    <Transaction>2005.10.20 04:00:18.974.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit1.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit9_data_structures.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.530.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.10.24 02:53:07.540.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.10.28 00:20:57.420.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.pas</Transaction>
+    <Transaction>2005.10.28 00:20:57.440.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit11_extractor.dfm</Transaction>
+    <Transaction>2005.12.18 11:32:06.823.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.pas</Transaction>
+    <Transaction>2005.12.18 11:32:06.833.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit12_ValueEdit.dfm</Transaction>
+    <Transaction>2005.12.22 16:36:15.685.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions_ABS.pas</Transaction>
+    <Transaction>2005.12.22 16:39:50.444.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.pas</Transaction>
+    <Transaction>2005.12.22 16:39:50.444.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.dfm</Transaction>
+    <Transaction>2005.12.24 01:01:39.626.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.pas</Transaction>
+    <Transaction>2005.12.24 01:01:39.656.dfm,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb_ABS.dfm=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit10_leveldb.dfm</Transaction>
+    <Transaction>2005.12.24 01:01:49.189.pas,C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions_ABS.pas=C:\Dokumente und Einstellungen\Administrator\Desktop\Oni\OniUnPacker\Unit2_functions.pas</Transaction>
+  </Transactions>
+</BorlandProject>
Index: /oup/releases/0.25a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.25a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.25a/src/OniUnPacker.cfg	(revision 8)
@@ -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.25a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.25a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.25a/src/OniUnPacker.dpr	(revision 8)
@@ -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.25a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.25a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.25a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.25a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.25a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,952 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit9_data_structures;
+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;
+  raw_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.CreateLevel(source,target:String);
+  VAR
+    i:LongWord;
+  BEGIN
+  END;
+
+PROCEDURE TForm10.CreateDatabase(source,target:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+  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:=target;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=loaded_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:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    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;
+
+        rawlist:=GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              mem:=TMemoryStream.Create;
+              filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+              filestream.Seek(rawlist[j].raw_addr,soFromBeginning);
+              mem.CopyFrom(filestream,rawlist[j].raw_size);
+              filestream.Free;
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") );';
+              Query.ExecSQL;
+              mem.Free;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        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 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 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 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 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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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',False,NIL);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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.25a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.25a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.25a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+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
+      MultiSelect = True
+      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.25a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.25a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit11_extractor.pas	(revision 8)
@@ -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.25a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.25a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.25a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.25a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.25a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,112 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.25a/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.25a/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.25a/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,327 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  Width = 650
+  Height = 667
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = 600
+      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 = 374
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 322
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 337
+        Width = 146
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.25a/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.25a/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,770 @@
+UNIT Unit13_rawedit;
+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, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    check_zerobyte: TCheckBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+  dat_offset:LongWord;
+  fileid_opened,dat_offset_opened:LongWord;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    LoadRawFilebyIDOffset(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_zerobyteClick(Sender: TObject);
+  VAR
+    i:Byte;
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
+    list_offset.Enabled:=True;
+    IF GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,6)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,6));
+    LoadRaw(GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of 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;
+          UpdateRawFile(GetRawInfo(fileid_opened,dat_offset_opened),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  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
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.25a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.25a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.25a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,180 @@
+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 ClosefileDB1: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = ClosefileDB1Click
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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.25a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.25a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,481 @@
+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, Unit13_rawedit;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    ClosefileDB1: TMenuItem;
+    procedure ClosefileDB1Click(Sender: TObject);
+    procedure menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+        END ELSE BEGIN
+          menu_convert.Enabled:=True;
+          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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+          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:=True;
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.ClosefileDB1Click(Sender: TObject);
+  BEGIN
+    menu_windows_closeallClick(Form1);
+    IF Length(tablist)=0 THEN BEGIN
+      IF opened_state=opened_db THEN CloseDatabase;
+      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: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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;
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.25a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.25a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,561 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data, 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,dat_offset,raw_addr,size:LongWord; target:Pointer):Boolean;
+FUNCTION LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; 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
+USES Unit4_Exporters, Unit9_data_structures;
+
+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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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:=Query.FieldByName('size').AsInteger;
+        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,dat_offset,raw_addr,size:LongWord; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      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)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      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 LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+  VAR
+    i:Byte;
+    raw_info:TRawInfo;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      raw_info:=GetRawInfo(fileid,dat_offset);
+      LoadRawFile(fileid,dat_offset,raw_info.raw_addr,raw_info.raw_size,target);
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Result:=True;
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenReadWrite);
+      filestream.Seek(rawinfo.raw_addr,soFromBeginning);
+      filestream.Write(target^,rawinfo.raw_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.25a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.25a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,110 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.25a';
+  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;
+
+  TRawInfo=RECORD
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+  END;
+  TRawList=Array OF TRawInfo;
+
+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.25a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.25a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit4_Exporters.pas	(revision 8)
@@ -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,$44,rawpos,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.25a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.25a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.25a/src/Unit5_preview.dfm	(revision 8)
@@ -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.25a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.25a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit5_preview.pas	(revision 8)
@@ -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.25a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.25a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,400 @@
+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;
+  VAR
+    img_addr:LongWord;
+  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);
+    LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr);
+
+    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,img_addr,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.25a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.25a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.25a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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.25a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.25a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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.25a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.25a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.25a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,296 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  Width = 650
+  Height = 450
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  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.25a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.25a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,722 @@
+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, Math;
+
+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 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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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, Unit13_rawedit;
+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]);
+      11: Result:='0x'+IntToHex(GetRawInfo(fileid,offset).raw_addr,8);
+      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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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;
+    i:LongWord;
+  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);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        edit_filtername.Text:=IntToStr(GetRawInfo(fileid,offset).raw_size);
+        IF Form1.open_child('rawedit') THEN BEGIN
+          TForm13(Form1.ActiveMDIChild).LoadRaw(GetRawInfo(fileid,offset));
+        END;
+        {LOAD RAW-EDITOR}
+      END;
+    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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.25a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.25a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.25a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,409 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, ABSMain, DB, ABSDecUtil, Unit3_data;
+
+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; 11: raw-addr; 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;
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+
+
+
+IMPLEMENTATION
+USES Unit2_functions;
+
+TYPE
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+VAR
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      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';
+      11: Result:='Raw-Address';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  VAR
+    i:LongWord;
+    raw_list:TRawList;
+  BEGIN
+    raw_list:=GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    FOR i:=0 TO High(raw_list) DO BEGIN
+      IF raw_list[i].src_offset=dat_offset THEN BEGIN
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Break;
+      END;
+    END;
+  END;
+
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+  VAR
+    i:LongWord;
+    Query:TABSQuery;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=1 TO Length(RawListHandlers) DO
+        IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN
+          IF RawListHandlers[i].needed THEN BEGIN
+            Result:=RawListHandlers[i].Handler(fileid);
+            Break;
+          END ELSE
+            Break;
+    END ELSE BEGIN
+      SetLength(Result,0);
+      Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i].src_id:=fileid;
+          Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger;
+          Result[i].raw_addr:=0;
+          Result[i].raw_size:=Query.FieldByName('size').AsInteger;
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$1C,4,@links);
+    links:=links*2;
+    SetLength(Result,links);
+    FOR i:=0 TO links-1 DO BEGIN
+      Result[i].src_offset:=$20+i*4;
+      LoadDatFilePart(fileid,$20+i*4,4,@link);
+      Result[i].raw_addr:=link;
+      Result[i].raw_size:=0{????????????????????????????????};
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$0C,4,@link);
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$40,4,@datasize);
+    LoadDatFilePart(fileid,$44,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$44;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,link:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    LoadDatFilePart(fileid,$18,4,@baselink);
+    LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      LoadDatFilePart(fileid,$20+(links-1)*4,4,@link);
+      SetLength(data,link+1024);
+      LoadRawFile(fileid,$1C,baselink,link+1024,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[link+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=link+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    LoadDatFilePart(fileid,$182,1,@tempb);
+    LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    LoadDatFilePart(fileid,$183,1,@tempb);
+    LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    LoadDatFilePart(fileid,$184,1,@tempb);
+    LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    LoadDatFilePart(fileid,$185,1,@tempb);
+    LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    LoadDatFilePart(fileid,$186,1,@tempb);
+    LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    LoadDatFilePart(fileid,$187,1,@tempb);
+    LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    LoadDatFilePart(fileid,$154,2,@tempw);
+    LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    LoadDatFilePart(fileid,$138,1,@templ);
+    LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      LoadRawFile(fileid,$34,link,$FFFF,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    LoadDatFilePart(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;
+    SetLength(Result,1);
+    Result[0].src_offset:=$9C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  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;
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+
+BEGIN
+  AddExtension('SUBT','Subtitles');
+  AddEntry('SUBT','ID',$00,4,'ID of this file');
+  AddEntry('SUBT','LevelID',$04,8,'ID of the level this file is in');
+  AddEntry('SUBT','Raw-Link',$18,11,'Address of the subtitle data in the .raw-file');
+  AddEntry('SUBT','Subtitle count',$1C,4,'Number of subtitles in this file');
+  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,11,'Address of the image data in the .raw-file');
+
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.27a/blubb.txt
===================================================================
--- /oup/releases/0.27a/blubb.txt	(revision 8)
+++ /oup/releases/0.27a/blubb.txt	(revision 8)
@@ -0,0 +1,6 @@
+___FILEINDEX___.txt
+
+
+TXMP:
+MipMapping: Bit0=an/aus
+ColorDepth: Bit0=??AnimationPic??, Bit1=shade vertex, Bit2=transparency, Bit4=16bit, Bit5=32bit
Index: /oup/releases/0.27a/changelog.txt
===================================================================
--- /oup/releases/0.27a/changelog.txt	(revision 8)
+++ /oup/releases/0.27a/changelog.txt	(revision 8)
@@ -0,0 +1,76 @@
+OniUnPacker v0.27a
+------------------
++Added MAC-file support
++Added StructureDefs for ONCCs / TRAMs (thanks to SSG)
+
+OniUnPacker v0.26a
+------------------
++Fixed some bugs again ;)
+
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.27a/src/Include_DataStructureDefs.pas
===================================================================
--- /oup/releases/0.27a/src/Include_DataStructureDefs.pas	(revision 8)
+++ /oup/releases/0.27a/src/Include_DataStructureDefs.pas	(revision 8)
@@ -0,0 +1,108 @@
+  AddExtension('ONCC','Oni character class');
+  AddEntry('ONCC','TXMP link',$28,8,'Shadow texture');
+  AddEntry('ONCC','Regeneration time',$64,2,'Regeneration time of one health point in 1/60 seconds if you use an hypo');
+  AddEntry('ONCC','Hurt light sound',$98,10032,'Reference to an OSBD file of level 0');
+  AddEntry('ONCC','Hurt medium sound',$B8,10032,'Reference to an OSBD file of level 0');
+  AddEntry('ONCC','Hurt heavy sound',$D8,10032,'Reference to an OSBD file of level 0');
+  AddEntry('ONCC','Death sound',$F8,10032,'Reference to an OSBD file of level 0');
+  AddEntry('ONCC','Taunt sound query',$2B0,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','"Who''s there?" sound query',$2B1,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','"I see you" sound query',$2B2,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','"You lose" sound query',$2B3,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','"Where are you?" sound query',$2B4,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','"Why is this happenung?" sound query',$2B5,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','Superpunch sound query',$2B6,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','Superkick sound query',$2B7,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','Super3 sound query',$2B8,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','Super4 sound query',$2B9,10,'00 = not used; 64 = used');
+  AddEntry('ONCC','Taunt sound',$2BC,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','"Who''s there?" sound',$2DC,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','"I see you" sound',$2FC,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','"You lose" sound',$31C,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','"Where are you?" sound',$33C,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','"Why is this happenung?" sound',$35C,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','Superpunch sound',$37C,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','Superkick sound',$39C,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','Super3 sound',$3BC,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','Super4 sound',$3DC,10032,'Reference to a SNDD file of level 0');
+  AddEntry('ONCC','Eyeshot',$3FC,9,'The max. distance where the AI can see you');
+  AddEntry('ONCC','Earshot',$400,9,'The max. distance where the AI can hear you');
+  AddEntry('ONCC','ONCV link',$434,8,'Character varient link');
+  AddEntry('ONCC','ONCP link',$438,8,'Character particle array link; useless?');
+  AddEntry('ONCC','ONIA link',$43C,8,'Character impact array link; useless?');
+  AddEntry('ONCC','Unknown',$444,10016,'Maybe the weight of the character?');
+  AddEntry('ONCC','Footstep walk impact',$454,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Footstep run impact',$4D6,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Footstep crouch impact',$558,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Fall slide impact',$5DA,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Fall land impact',$65C,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Fall land hard impact',$6DE,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Fall knockdown impact',$760,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Fall knockdown impact',$7E2,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Fall knockdown impact',$864,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Footstep turn impact',$8E6,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Footstep run start impact',$968,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Footstep single step impact',$9EA,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Footstep run stop impact',$A6C,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Footstep walk stop impact',$AEE,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Footstep run sprint impact',$B70,10128,'Reference to the a Impt file of level 0');
+  AddEntry('ONCC','Unknown',$BF4,10064,'special death particles; only the mad bomber use it');
+  AddEntry('ONCC','TRBS link',$C3C,8,'Body set link');
+  AddEntry('ONCC','TRMA link',$C40,8,'Texture map array link');
+  AddEntry('ONCC','CBPM link',$C44,8,'Body part material link');
+  AddEntry('ONCC','CBPI link',$C48,8,'Body part impact link');
+  AddEntry('ONCC','Basic health',$C58,4,'Extra health informations are stored in the Character.BINA files');
+  AddEntry('ONCC','Minimal body size factor',$C5C,9,'Minimal body size factor');
+  AddEntry('ONCC','Maximal body size factor',$C60,9,'Maximal body size factor');
+  AddEntry('ONCC','TRAC link',$C88,8,'Animation collection link');
+  AddEntry('ONCC','TRSC link',$C8C,8,'Screen (aiming) collection link');
+
+  AddExtension('TRAM','Totoro Animation Sequence (Totoro is the name of the character animation engine.)');
+  AddEntry('TRAM','Raw link',$0C,11,'Address of the y-position data in the .raw-file');
+  AddEntry('TRAM','Raw link',$10,11,'Address of the x-z-position data in the .raw-file');
+  AddEntry('TRAM','Raw link',$14,11,'Address of the attack data in the .raw-file');
+  AddEntry('TRAM','Raw link',$18,11,'Address of the damage data in the .raw-file');
+  AddEntry('TRAM','Raw link',$1C,11,'Address of the motion blur data in the .raw-file');
+  AddEntry('TRAM','Raw link',$20,11,'Address of the shortcut data in the .raw-file');
+  AddEntry('TRAM','Raw link',$24,11,'Address of the throw data in the .raw-file');
+  AddEntry('TRAM','Raw link',$28,11,'Address of the footstep data in the .raw-file');
+  AddEntry('TRAM','Raw link',$2C,11,'Address of the particle data in the .raw-file');
+  AddEntry('TRAM','Raw link',$30,11,'Address of the position data in the .raw-file');
+  AddEntry('TRAM','Raw link',$34,11,'Address of the bodypart animation data in the .raw-file');
+  AddEntry('TRAM','Raw link',$38,11,'Address of the sound data in the .raw-file');
+  AddEntry('TRAM','Flags',$3C,8,'Flags; It seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets');
+  AddEntry('TRAM','TRAM link',$40,8,'First direct animation link; this animation follows after a left mouse click (punch)');
+  AddEntry('TRAM','TRAM link',$44,8,'Second direct animation link; this animation follows after a right mouse click (kick)');
+  AddEntry('TRAM','Used parts',$48,8,'Used for weapon animations like recoil, reload, draw weapon, etc.');
+  AddEntry('TRAM','Replace parts',$4C,8,'Used for weapon animations like recoil, reload, draw weapon, etc.');
+  AddEntry('TRAM','Final rotation',$50,9,'Final rotation; stored as multiples of the number "pi" (3.141592...)');
+  AddEntry('TRAM','Move direction',$54,2,'Move direction');
+  AddEntry('TRAM','Attack voice sound',$56,2,'Attack voice sound (f.e. Konoko''s "Rising fury!")');
+  AddEntry('TRAM','Extent packages',$138,4,'Amount of packages of the extent data');
+  AddEntry('TRAM','Raw link',$13C,11,'Address of the extent data in the .raw-file');
+  AddEntry('TRAM','Attack sound',$140,10016,'Reference to an attack sound (f.e. "slap") of level 0');
+  AddEntry('TRAM','Hard pause',$150,2,'Hard pause in 1/60 seconds');
+  AddEntry('TRAM','Soft pause',$152,2,'Soft pause in 1/60 seconds');
+  AddEntry('TRAM','Frames',$15E,2,'Frames per second');
+  AddEntry('TRAM','Compression',$160,2,'Compression size');
+  AddEntry('TRAM','Type',$162,2,'ID for the animation of the opponent');
+  AddEntry('TRAM','Animation Type',$164,2,'ID for the animation of the opponent');
+  AddEntry('TRAM','From state',$166,2,'From state');
+  AddEntry('TRAM','To state',$168,2,'To state');
+  AddEntry('TRAM','Bodyparts',$16A,2,'Amount of bodyparts');
+  AddEntry('TRAM','Frames',$16C,2,'Animation length in frames');
+  AddEntry('TRAM','Duration',$16E,2,'Duration of the animation in frames');
+  AddEntry('TRAM','Varient',$170,2,'Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short');
+  AddEntry('TRAM','Varient end',$172,2,'Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short');
+  AddEntry('TRAM','Atomic start',$174,2,'Atomic start');
+  AddEntry('TRAM','Atomic end',$176,2,'Atomic end');
+  AddEntry('TRAM','End interpolation',$178,2,'End interpolation');
+  AddEntry('TRAM','Maximal interpolation',$17A,2,'Maximal interpolation');
+  AddEntry('TRAM','Action frame',$17C,6,'Action frame; at this frame starts the "real" animation');
+  AddEntry('TRAM','First level',$17E,2,'First level; the level where you can use this animation the first time');
+  AddEntry('TRAM','Attack packages',$182,1,'Amount of packages of the attack data');
+  AddEntry('TRAM','Damage packages',$183,1,'Amount of packages of the damage data');
+  AddEntry('TRAM','Motion blur packages',$184,1,'Amount of packages of the motion blur data');
+  AddEntry('TRAM','Shortcut packages',$185,1,'Amount of packages of the shortcut data');
+  AddEntry('TRAM','Footstep packages',$186,1,'Amount of packages of the footstep data');
+  AddEntry('TRAM','Particle packages',$187,1,'Amount of packages of the particle data');
Index: /oup/releases/0.27a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.27a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.27a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,181 @@
+﻿<?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 Name="UnitInitSeq">True</Compiler>
+      <Compiler Name="LocalPInvoke">True</Compiler>
+      <Compiler Name="CodePage"></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 Name="GenerateHpps">False</Linker>
+    </Linker>
+		<Directories>
+			<Directories Name="OutputDir">exe</Directories>
+			<Directories Name="UnitOutputDir">dcu</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 Name="Debug Symbols Search Path"></Parameters>
+      <Parameters Name="LoadAllSymbols">True</Parameters>
+      <Parameters Name="LoadUnspecifiedSymbols">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>  <Language>
+      <Language Name="ActiveLang"></Language>
+      <Language Name="ProjectLang">$00000000</Language>
+      <Language Name="RootDir"></Language>
+    </Language>
+    
+    <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.27a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.27a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.27a/src/OniUnPacker.cfg	(revision 8)
@@ -0,0 +1,40 @@
+-$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
+-E"exe"
+-N0"dcu"
+-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.27a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.27a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.27a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,27 @@
+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},
+  Unit13_rawedit in 'Unit13_rawedit.pas' {Form13};
+
+{$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.27a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.27a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.27a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.27a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.27a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,952 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit9_data_structures;
+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;
+  raw_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.CreateLevel(source,target:String);
+  VAR
+    i:LongWord;
+  BEGIN
+  END;
+
+PROCEDURE TForm10.CreateDatabase(source,target:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+  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:=target;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=loaded_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:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    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;
+
+        rawlist:=GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              mem:=TMemoryStream.Create;
+              filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+              filestream.Seek(rawlist[j].raw_addr,soFromBeginning);
+              mem.CopyFrom(filestream,rawlist[j].raw_size);
+              filestream.Free;
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") );';
+              Query.ExecSQL;
+              mem.Free;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        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 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 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 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 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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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',False,NIL);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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.27a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.27a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.27a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+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
+      MultiSelect = True
+      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.27a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.27a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit11_extractor.pas	(revision 8)
@@ -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.27a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.27a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.27a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.27a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.27a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,112 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.27a/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.27a/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.27a/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,323 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  ClientHeight = 640
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = 600
+      Width = 483
+      Height = 40
+      Align = alBottom
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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 = 374
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 337
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 352
+        Width = 146
+        Height = 88
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        OnResize = panel_extensionResize
+        object lbl_filter: TLabel
+          Left = 2
+          Top = 46
+          Width = 100
+          Height = 17
+          AutoSize = False
+          Caption = 'Filter by &extension:'
+          FocusControl = combo_extension
+        end
+        object combo_extension: TComboBox
+          Left = 2
+          Top = 60
+          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 = 2
+          OnClick = combo_extensionClick
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.27a/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.27a/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,783 @@
+UNIT Unit13_rawedit;
+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, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+  dat_offset:LongWord;
+  fileid_opened,dat_offset_opened:LongWord;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    IF list_offset.Count=0 THEN BEGIN
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF StrToInt(MidStr(list.Items.Strings[i],1,5))=raw_info.src_id THEN BEGIN
+          list.ItemIndex:=i;
+          listClick(Self);
+          Break;
+        END;
+      END;
+      FOR i:=0 TO list_offset.Count-1 DO BEGIN
+        IF MidStr(list_offset.Items.Strings[i],3,8)=IntToHex(raw_info.src_offset,8) THEN BEGIN
+          list_offset.ItemIndex:=i;
+          Break;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    LoadRawFilebyIDOffset(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.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(RawListHandlers) DO
+      combo_extension.Items.Add(RawListHandlers[i].ext);
+//    FOR i:=0 TO High(exts) DO
+//      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm13.LoadFileNames;
+  VAR
+    Extension:String;
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN BEGIN
+      Extension:='';
+      FOR i:=0 TO High(RawListHandlers) DO BEGIN
+        IF Length(Extension)>0 THEN Extension:=Extension+',';
+        Extension:=Extension+RawListHandlers[i].Ext;
+      END;
+    END;
+
+    files:=GetFilesList(extension,pattern,TRUE);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
+    list_offset.Enabled:=True;
+    IF GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,8)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,8));
+    LoadRaw(GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of 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;
+          UpdateRawFile(GetRawInfo(fileid_opened,dat_offset_opened),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  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
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.27a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.27a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.27a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,180 @@
+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 ClosefileDB1: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = ClosefileDB1Click
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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.27a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.27a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,481 @@
+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, Unit13_rawedit;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    ClosefileDB1: TMenuItem;
+    procedure ClosefileDB1Click(Sender: TObject);
+    procedure menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+        END ELSE BEGIN
+          menu_convert.Enabled:=True;
+          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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+          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:=True;
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.ClosefileDB1Click(Sender: TObject);
+  BEGIN
+    menu_windows_closeallClick(Form1);
+    IF Length(tablist)=0 THEN BEGIN
+      IF opened_state=opened_db THEN CloseDatabase;
+      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: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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;
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.27a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.27a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,599 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data, 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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+FUNCTION LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; 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
+USES Unit4_Exporters, Unit9_data_structures;
+
+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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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:=Query.FieldByName('size').AsInteger;
+        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;
+    where_ext: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 (Pos(dat_files[i].Extension,ext)>0) ) 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 ';
+        IF Pos(',',ext)>0 THEN BEGIN
+          i:=1;
+          where_ext:='';
+          WHILE i<Length(ext) DO BEGIN
+            IF Length(where_ext)>0 THEN where_ext:=where_ext+' OR ';
+            where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")';
+            i:=i+5;
+          END;
+          where:=where+'('+where_ext+')';
+        END ELSE BEGIN
+          where:=where+'(extension="'+ext+'")';
+        END;
+      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;
+    header_pc,header_mac:Boolean;
+  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));
+    header_pc:=True;
+    header_mac:=True;
+    FOR i:=0 TO High(dat_header.Ident) DO BEGIN
+      IF dat_header.Ident[i]<>header_ident1_pc[i] THEN BEGIN
+        header_pc:=False;
+      END;
+      IF dat_header.Ident[i]<>header_ident1_mac[i] THEN BEGIN
+        header_mac:=False;
+      END;
+    END;
+    IF NOT (header_pc OR header_mac) THEN BEGIN
+      Result:=False;
+      Exit;
+    END ELSE BEGIN
+      IF (header_pc AND NOT header_mac) THEN
+        dat_os_mac:=False
+      ELSE
+        IF (NOT header_pc AND header_mac) THEN
+          dat_os_mac:=True
+        ELSE BEGIN
+          Result:=False;
+          Exit;
+        END;
+    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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),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)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      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 LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+  VAR
+    i:Byte;
+    raw_info:TRawInfo;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      raw_info:=GetRawInfo(fileid,dat_offset);
+      LoadRawFile(fileid,dat_offset,raw_info.raw_addr,raw_info.raw_size,raw_info.loc_sep,target);
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Result:=True;
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT rawinfo.loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenReadWrite)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),fmOpenReadWrite);
+      filestream.Seek(rawinfo.raw_addr,soFromBeginning);
+      filestream.Write(target^,rawinfo.raw_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.27a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.27a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,114 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.27a';
+  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;
+
+  TRawInfo=RECORD
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+    loc_sep:Boolean;
+  END;
+  TRawList=Array OF TRawInfo;
+
+VAR
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_os_mac:Boolean=False;
+  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_pc: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_ident1_mac:Array[0..$13] OF Byte=
+      ($61,$30,$C1,$23,$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.27a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.27a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit4_Exporters.pas	(revision 8)
@@ -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,$44,rawpos,Length(data),False,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.27a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.27a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.27a/src/Unit5_preview.dfm	(revision 8)
@@ -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.27a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.27a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit5_preview.pas	(revision 8)
@@ -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.27a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.27a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,406 @@
+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;
+  VAR
+    img_addr:LongWord;
+  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);
+    IF NOT dat_os_mac THEN
+      LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr)
+    ELSE
+      LoadDatFilePart(fileid,$A0,SizeOf(img_addr),@img_addr);
+
+    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);
+
+    IF NOT dat_os_mac THEN
+      LoadRawFile(fileid,$9C,img_addr,Result.datasize,dat_os_mac,@Result.imgdata[0])
+    ELSE
+      LoadRawFile(fileid,$A0,img_addr,Result.datasize,dat_os_mac,@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.27a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.27a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.27a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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 = 'MIP Mapping'
+      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.27a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.27a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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.27a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.27a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.27a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,301 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 423
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  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
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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.27a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.27a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,724 @@
+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, Math;
+
+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 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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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, Unit13_rawedit;
+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]);
+      11: Result:='0x'+IntToHex(GetRawInfo(fileid,offset).raw_addr,8);
+      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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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;
+    i:LongWord;
+  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);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        IF GetRawInfo(fileid,offset).raw_size>0 THEN BEGIN
+        //edit_filtername.Text:=IntToStr(GetRawInfo(fileid,offset).raw_size);
+          IF Form1.open_child('rawedit') THEN BEGIN
+            TForm13(Form1.ActiveMDIChild).LoadRaw(GetRawInfo(fileid,offset));
+          END;
+        END;
+        {LOAD RAW-EDITOR}
+      END;
+    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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.27a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.27a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.27a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,423 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, ABSMain, DB, ABSDecUtil, Unit3_data;
+
+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; 11: raw-addr; 10000+: string[0+]
+      description:String;
+    END;
+  Tstructure_info=RECORD
+      extension:String;
+      typedesc:String;
+      entries:Array OF Tstructure_entry;
+    END;
+  Tstructures=Array OF Tstructure_info;
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+
+VAR
+  structure_infos:Tstructures;
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+
+
+
+IMPLEMENTATION
+USES Unit2_functions;
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      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';
+      11: Result:='Raw-Address';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  VAR
+    i:LongWord;
+    raw_list:TRawList;
+  BEGIN
+    raw_list:=GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    FOR i:=0 TO High(raw_list) DO BEGIN
+      IF raw_list[i].src_offset=dat_offset THEN BEGIN
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Result.loc_sep:=raw_list[i].loc_sep;
+        Break;
+      END;
+    END;
+  END;
+
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+  VAR
+    i:LongWord;
+    Query:TABSQuery;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=0 TO High(RawListHandlers) DO
+        IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN
+          IF RawListHandlers[i].needed THEN BEGIN
+            Result:=RawListHandlers[i].Handler(fileid);
+            Break;
+          END ELSE
+            Break;
+    END ELSE BEGIN
+      SetLength(Result,0);
+      Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i].src_id:=fileid;
+          Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger;
+          Result[i].raw_addr:=0;
+          Result[i].raw_size:=Query.FieldByName('size').AsInteger;
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*4;
+        LoadDatFilePart(fileid,$20+i*4,4,@link);
+        Result[i].raw_addr:=link;
+        Result[i].raw_size:=0{????????????????????????????????};
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$0C,4,@link);
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$40,4,@datasize);
+    LoadDatFilePart(fileid,$44,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$44;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,link:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    LoadDatFilePart(fileid,$18,4,@baselink);
+    LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      LoadDatFilePart(fileid,$20+(links-1)*4,4,@link);
+      SetLength(data,link+1024);
+      LoadRawFile(fileid,$1C,baselink,link+1024,False,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[link+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=link+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    LoadDatFilePart(fileid,$182,1,@tempb);
+    LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    LoadDatFilePart(fileid,$183,1,@tempb);
+    LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    LoadDatFilePart(fileid,$184,1,@tempb);
+    LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    LoadDatFilePart(fileid,$185,1,@tempb);
+    LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    LoadDatFilePart(fileid,$186,1,@tempb);
+    LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    LoadDatFilePart(fileid,$187,1,@tempb);
+    LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    LoadDatFilePart(fileid,$154,2,@tempw);
+    LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    LoadDatFilePart(fileid,$138,1,@templ);
+    LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link_pc:LongWord;
+    link_mac:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    LoadDatFilePart(fileid,$9C,4,@link_pc);
+    LoadDatFilePart(fileid,$A0,4,@link_mac);
+    CASE storetype OF
+      0,1,2: datasize:=x*y*2;
+      8: datasize:=x*y*4;
+      9: datasize:=x*y DIV 2;
+    END;
+    SetLength(Result,1);
+    IF NOT dat_os_mac THEN BEGIN
+      Result[0].src_offset:=$9C;
+      Result[0].raw_addr:=link_pc
+    END ELSE BEGIN
+      Result[0].src_offset:=$A0;
+      Result[0].raw_addr:=link_mac;
+    END;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  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;
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+
+BEGIN
+  AddExtension('SUBT','Subtitles');
+  AddEntry('SUBT','ID',$00,4,'ID of this file');
+  AddEntry('SUBT','LevelID',$04,8,'ID of the level this file is in');
+  AddEntry('SUBT','Raw-Link',$18,11,'Address of the subtitle data in the .raw-file');
+  AddEntry('SUBT','Subtitle count',$1C,4,'Number of subtitles in this file');
+  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','MIP Mapping',$88,10,'MIP Mapping 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,11,'Address of the image data in the .raw-file (only for PC-dat-files)');
+  AddEntry('TXMP','Raw-Link',$A0,11,'Address of the image data in the .raw-file (only for MAC-dat-files)');
+
+{$I Include_DataStructureDefs.pas}
+
+//  InsertRawListHandler('AGDB',True,AGDB);
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.27a/todo.txt
===================================================================
--- /oup/releases/0.27a/todo.txt	(revision 8)
+++ /oup/releases/0.27a/todo.txt	(revision 8)
@@ -0,0 +1,157 @@
+Unit10 unabhängig, funktionsweise wiederherstellen
+Schreibt auch die dat_files[] etc
+Benutzt die *globalen* dat_stream/raw_stream und keine MemCopy
+
+
+ValueViewer: Offset
+
+TXMPReplace: Zugriff über Unit2
+
+
+SELECT [src_id],MIN(datfiles.[name]),SUM(rawmap.[size]) FROM rawmap INNER  JOIN datfiles ON datfiles.[id]=[src_id] GROUP BY [src_id] ORDER BY [src_id] ASC
+
+Extrahier-Ordner-Option (mit Platzhalter für .dat-Name)
+
+-HELP.hlp
+-About
+
+-BinEdit: Zusatzfunktionen wie: Suche, 
+-BinEdit: Bild/Menu/Button irgendwas zum speichern
+
+-Extractor: Wohin?
+
+-FileCompare: Ergebnis=Tabelle, jede Zeile eine differenz-addresse, spalten = werte an addr. für compared files
+
+-TXMP-Replace: MultiReplace
+
+-Move-Freischalter (Mindestlvl eingabe)
+
+-Löschen einer Datei auf die gelinkt wird: Liste der Links und sicherheitsfrage
+
+-Filebox-Context: Extract etc
+
+-DAT geladen -> Meldung oder sogar "what to do next?"
+-SSG: Levels extrahieren?
+-Pierre: Wie Char-Anims, Char-Models, Levels extrahieren?
+-Language-Files?
+-STRG+C auf Dateilisten etc für kopieren des Namens
+
+-REPACKING: testen lvl0: 690-collisions.txmp einbauen, script: collisions-zeug
+
+#################################################################
+##########                 File-Types                  ##########
+#################################################################
+(3CLA)
+ABNA
+AGDB
+AGQC
+AGQG
+(AGQM)
+AGQR
+AISA
+AITR
+(AIWA)
+AKAA
+AKBA
+AKBP
+AKDA
+AKEV
+AKOT
+AKVA
+BINA
+CBPI
+CBPM
+CONS
+CRSA
+DOOR
+DPge
+(EDIA)
+ENVP
+FILM
+(FXLR)
+(GMAN)
+HPge
+IDXA
+IGHH
+IGPA
+IGPG
+IGSA
+IGSt
+Impt
+IPge
+KeyI
+M3GA
+M3GM
+(M3TA)
+Mtrl
+(NMSA)
+OBAN
+OBDC
+(OBLS)
+OBOA
+OFGA
+ONCC
+ONCP
+ONCV
+ONFA
+ONGS
+ONIA
+ONLD
+ONLV
+ONMA
+ONOA
+ONSA
+ONSK
+ONTA
+ONVL
+ONWC
+OPge
+OSBD
+OTIT
+OTLF
+PLEA
+PNTA
+PSpc
+PSpL
+PSUI
+QTNA
+(QUDA)
+SNDD
+StNA
+SUBT
+(TMFA)
+(TMRA)
+TRAC
+TRAM
+TRAS
+TRBS
+TRCM
+(TRFT)
+TRGA
+TRGE
+TRIA
+TRIG
+TRMA
+TRSC
+TRTA
+TSFF
+TSFL
+TSFT
+TSGA
+TStr
+TURR
+TXAN
+TXCA
+TXMA
+TXMB
+TXMP
+(TXPC)
+TxtC
+(UUEA)
+(UVDL)
+VCRA
+WMCL
+WMDD
+WMM_
+WMMB
+WPge
Index: /oup/releases/0.28a/StructDefs/ONCC.txt
===================================================================
--- /oup/releases/0.28a/StructDefs/ONCC.txt	(revision 8)
+++ /oup/releases/0.28a/StructDefs/ONCC.txt	(revision 8)
@@ -0,0 +1,58 @@
+Oni character class
+TXMP link	$28	8	Shadow texture
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use an hypo
+Hurt light sound	$98	10032	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	10032	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	10032	Reference to an OSBD file of level 0
+Death sound	$F8	10032	Reference to an OSBD file of level 0
+Taunt sound query	$2B0	10	00 = not used; 64 = used
+"Whos there?" sound query	$2B1	10	00 = not used; 64 = used
+"I see you" sound query	$2B2	10	00 = not used; 64 = used
+"You lose" sound query	$2B3	10	00 = not used; 64 = used
+"Where are you?" sound query	$2B4	10	00 = not used; 64 = used
+"Why is this happenung?" sound query	$2B5	10	00 = not used; 64 = used
+Superpunch sound query	$2B6	10	00 = not used; 64 = used
+Superkick sound query	$2B7	10	00 = not used; 64 = used
+Super3 sound query	$2B8	10	00 = not used; 64 = used
+Super4 sound query	$2B9	10	00 = not used; 64 = used
+Taunt sound	$2BC	10032	Reference to a SNDD file of level 0
+"Whos there?" sound	$2DC	10032	Reference to a SNDD file of level 0
+"I see you" sound	$2FC	10032	Reference to a SNDD file of level 0
+"You lose" sound	$31C	10032	Reference to a SNDD file of level 0
+"Where are you?" sound	$33C	10032	Reference to a SNDD file of level 0
+"Why is this happenung?" sound	$35C	10032	Reference to a SNDD file of level 0
+Superpunch sound	$37C	10032	Reference to a SNDD file of level 0
+Superkick sound	$39C	10032	Reference to a SNDD file of level 0
+Super3 sound	$3BC	10032	Reference to a SNDD file of level 0
+Super4 sound	$3DC	10032	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV link	$434	8	Character varient link
+ONCP link	$438	8	Character particle array link; useless?
+ONIA link	$43C	8	Character impact array link; useless?
+Unknown	$444	10016	Maybe the weight of the character?
+Footstep walk impact	$454	10128	Reference to the a Impt file of level 0
+Footstep run impact	$4D6	10128	Reference to the a Impt file of level 0
+Footstep crouch impact	$558	10128	Reference to the a Impt file of level 0
+Fall slide impact	$5DA	10128	Reference to the a Impt file of level 0
+Fall land impact	$65C	10128	Reference to the a Impt file of level 0
+Fall land hard impact	$6DE	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$760	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$7E2	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$864	10128	Reference to the a Impt file of level 0
+Footstep turn impact	$8E6	10128	Reference to the a Impt file of level 0
+Footstep run start impact	$968	10128	Reference to the a Impt file of level 0
+Footstep single step impact	$9EA	10128	Reference to the a Impt file of level 0
+Footstep run stop impact	$A6C	10128	Reference to the a Impt file of level 0
+Footstep walk stop impact	$AEE	10128	Reference to the a Impt file of level 0
+Footstep run sprint impact	$B70	10128	Reference to the a Impt file of level 0
+Unknown	$BF4	10064	special death particles; only the mad bomber use it
+TRBS link	$C3C	8	Body set link
+TRMA link	$C40	8	Texture map array link
+CBPM link	$C44	8	Body part material link
+CBPI link	$C48	8	Body part impact link
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC link	$C88	8	Animation collection link
+TRSC link	$C8C	8	Screen (aiming) collection link
Index: /oup/releases/0.28a/StructDefs/SUBT.txt
===================================================================
--- /oup/releases/0.28a/StructDefs/SUBT.txt	(revision 8)
+++ /oup/releases/0.28a/StructDefs/SUBT.txt	(revision 8)
@@ -0,0 +1,5 @@
+Subtitles
+ID	$00	4	ID of this file
+LevelID	$04	8	ID of the level this file is in
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Subtitle count	$1C	4	Number of subtitles in this file
Index: /oup/releases/0.28a/StructDefs/TRAM.txt
===================================================================
--- /oup/releases/0.28a/StructDefs/TRAM.txt	(revision 8)
+++ /oup/releases/0.28a/StructDefs/TRAM.txt	(revision 8)
@@ -0,0 +1,49 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	8	Flags; It seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	8	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	8	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	2	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	10016	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	6	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
Index: /oup/releases/0.28a/StructDefs/TXMP.txt
===================================================================
--- /oup/releases/0.28a/StructDefs/TXMP.txt	(revision 8)
+++ /oup/releases/0.28a/StructDefs/TXMP.txt	(revision 8)
@@ -0,0 +1,13 @@
+Texture
+ID	$00	4	ID of this file
+LevelID	$04	8	ID of the level this file is in
+FileName	$08	10128	
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	8	Link to the TXAN-file (if this TXMP is the first image of an animation)
+TXMP-Link	$98	8	Link to another TXMP-file
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
Index: /oup/releases/0.28a/blubb.txt
===================================================================
--- /oup/releases/0.28a/blubb.txt	(revision 8)
+++ /oup/releases/0.28a/blubb.txt	(revision 8)
@@ -0,0 +1,6 @@
+___FILEINDEX___.txt
+
+
+TXMP:
+MipMapping: Bit0=an/aus
+ColorDepth: Bit0=??AnimationPic??, Bit1=shade vertex, Bit2=transparency, Bit4=16bit, Bit5=32bit
Index: /oup/releases/0.28a/changelog.txt
===================================================================
--- /oup/releases/0.28a/changelog.txt	(revision 8)
+++ /oup/releases/0.28a/changelog.txt	(revision 8)
@@ -0,0 +1,82 @@
+OniUnPacker v0.28a
+------------------
++StructureDefinitions as separate txt-files
++Minor bugfixes
++Ctrl+C for Hex-fields
+
+OniUnPacker v0.27a
+------------------
++Added MAC-file support
++Added StructureDefs for ONCCs / TRAMs (thanks to SSG)
+
+OniUnPacker v0.26a
+------------------
++Fixed some bugs again ;)
+
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.28a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.28a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.28a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,181 @@
+﻿<?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 Name="UnitInitSeq">True</Compiler>
+      <Compiler Name="LocalPInvoke">True</Compiler>
+      <Compiler Name="CodePage"></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 Name="GenerateHpps">False</Linker>
+    </Linker>
+		<Directories>
+			<Directories Name="OutputDir">exe</Directories>
+			<Directories Name="UnitOutputDir">dcu</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 Name="Debug Symbols Search Path"></Parameters>
+      <Parameters Name="LoadAllSymbols">True</Parameters>
+      <Parameters Name="LoadUnspecifiedSymbols">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>  <Language>
+      <Language Name="ActiveLang"></Language>
+      <Language Name="ProjectLang">$00000000</Language>
+      <Language Name="RootDir"></Language>
+    </Language>
+    
+    <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.28a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.28a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.28a/src/OniUnPacker.cfg	(revision 8)
@@ -0,0 +1,40 @@
+-$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
+-E"exe"
+-N0"dcu"
+-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.28a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.28a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.28a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,27 @@
+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},
+  Unit13_rawedit in 'Unit13_rawedit.pas' {Form13};
+
+{$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.28a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.28a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.28a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.28a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.28a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,952 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit9_data_structures;
+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;
+  raw_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.CreateLevel(source,target:String);
+  VAR
+    i:LongWord;
+  BEGIN
+  END;
+
+PROCEDURE TForm10.CreateDatabase(source,target:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+  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:=target;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=loaded_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:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    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;
+
+        rawlist:=GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              mem:=TMemoryStream.Create;
+              filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+              filestream.Seek(rawlist[j].raw_addr,soFromBeginning);
+              mem.CopyFrom(filestream,rawlist[j].raw_size);
+              filestream.Free;
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") );';
+              Query.ExecSQL;
+              mem.Free;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        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 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 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 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 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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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',False,NIL);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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.28a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.28a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.28a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+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
+      MultiSelect = True
+      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.28a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.28a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit11_extractor.pas	(revision 8)
@@ -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.28a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.28a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.28a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.28a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.28a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,112 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.28a/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.28a/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.28a/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,324 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  ClientHeight = 640
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = []
+      OnKeyUp = hexKeyUp
+      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 = 600
+      Width = 483
+      Height = 40
+      Align = alBottom
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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 = 374
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 337
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 352
+        Width = 146
+        Height = 88
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        OnResize = panel_extensionResize
+        object lbl_filter: TLabel
+          Left = 2
+          Top = 46
+          Width = 100
+          Height = 17
+          AutoSize = False
+          Caption = 'Filter by &extension:'
+          FocusControl = combo_extension
+        end
+        object combo_extension: TComboBox
+          Left = 2
+          Top = 60
+          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 = 2
+          OnClick = combo_extensionClick
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.28a/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.28a/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,806 @@
+UNIT Unit13_rawedit;
+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, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+  dat_offset:LongWord;
+  fileid_opened,dat_offset_opened:LongWord;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    IF list_offset.Count=0 THEN BEGIN
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF StrToInt(MidStr(list.Items.Strings[i],1,5))=raw_info.src_id THEN BEGIN
+          list.ItemIndex:=i;
+          listClick(Self);
+          Break;
+        END;
+      END;
+      FOR i:=0 TO list_offset.Count-1 DO BEGIN
+        IF MidStr(list_offset.Items.Strings[i],3,8)=IntToHex(raw_info.src_offset,8) THEN BEGIN
+          list_offset.ItemIndex:=i;
+          Break;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    LoadRawFilebyIDOffset(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.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(RawListHandlers) DO
+      combo_extension.Items.Add(RawListHandlers[i].ext);
+//    FOR i:=0 TO High(exts) DO
+//      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm13.LoadFileNames;
+  VAR
+    Extension:String;
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN BEGIN
+      Extension:='';
+      FOR i:=0 TO High(RawListHandlers) DO BEGIN
+        IF Length(Extension)>0 THEN Extension:=Extension+',';
+        Extension:=Extension+RawListHandlers[i].Ext;
+      END;
+    END;
+
+    files:=GetFilesList(extension,pattern,TRUE);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=StrToInt(MidStr(list.Items.Strings[list.ItemIndex],1,5));
+    list_offset.Enabled:=True;
+    IF GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,8)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,8));
+    LoadRaw(GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of 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;
+          UpdateRawFile(GetRawInfo(fileid_opened,dat_offset_opened),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm13.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  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
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.28a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.28a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.28a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,179 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = 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 ClosefileDB1: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = ClosefileDB1Click
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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.28a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.28a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,482 @@
+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, Unit9_data_structures,
+  Unit10_leveldb, Unit4_exporters,
+  Unit5_preview, Unit7_txmpreplace, Unit8_binedit, Unit11_extractor, Unit13_rawedit;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    ClosefileDB1: TMenuItem;
+    PROCEDURE ClosefileDB1Click(Sender: TObject);
+    PROCEDURE menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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;
+    LoadStructureDefinitions(ExtractFilepath(Application.EXEname)+'\StructDefs');
+  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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+        END ELSE BEGIN
+          menu_convert.Enabled:=True;
+          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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+          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:=True;
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.ClosefileDB1Click(Sender: TObject);
+  BEGIN
+    menu_windows_closeallClick(Form1);
+    IF Length(tablist)=0 THEN BEGIN
+      IF opened_state=opened_db THEN CloseDatabase;
+      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: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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;
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.28a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.28a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,652 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data, 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 HexToLong(hex:String):LongWord;
+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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+FUNCTION LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; 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;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringList;
+
+
+IMPLEMENTATION
+USES Unit4_Exporters, Unit9_data_structures;
+
+VAR
+  Database:TABSDatabase;
+  Query:TABSQuery;
+
+TYPE
+  TValueSwitcher=Record
+    CASE IsFloat: Boolean OF
+      True: (ValueFloat:Single);
+      False: (ValueInt:LongWord);
+  END;
+
+FUNCTION NormalizeHexString(VAR hex:String):Boolean;
+  VAR
+    i:Byte;
+  BEGIN
+    IF hex[1]='$' THEN BEGIN
+      FOR i:=1 TO Length(hex)-1 DO BEGIN
+        hex[i]:=hex[i+1];
+      END;
+      SetLength(hex, Length(hex)-1);
+    END;
+    IF (hex[1]='0') AND (UpCase(hex[2])='X') THEN BEGIN
+      FOR i:=1 TO Length(hex)-2 DO BEGIN
+        hex[i]:=hex[i+2];
+      END;
+      SetLength(hex, Length(hex)-2);
+    END;
+    IF Length(hex)=0 THEN
+      Result:=False
+    ELSE
+      Result:=True;
+  END;
+
+FUNCTION HexToLong(hex:String):LongWord;
+  VAR
+    i:Byte;
+  BEGIN
+    IF NormalizeHexString(hex) THEN BEGIN
+      hex:=UpperCase(hex);
+      Result:=0;
+      FOR i:=1 TO Length(hex) DO BEGIN
+        Result:=Result SHL 4;
+        CASE hex[i] OF
+          '0'..'9': Result:=Result+Ord(hex[i])-48;
+          'A'..'F': Result:=Result+Ord(hex[i])-55;
+        ELSE
+          Result:=0;
+          Exit;
+        END;
+      END;
+    END ELSE BEGIN
+      Result:=0;
+    END;
+  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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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:=Query.FieldByName('size').AsInteger;
+        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;
+    where_ext: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 (Pos(dat_files[i].Extension,ext)>0) ) 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 ';
+        IF Pos(',',ext)>0 THEN BEGIN
+          i:=1;
+          where_ext:='';
+          WHILE i<Length(ext) DO BEGIN
+            IF Length(where_ext)>0 THEN where_ext:=where_ext+' OR ';
+            where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")';
+            i:=i+5;
+          END;
+          where:=where+'('+where_ext+')';
+        END ELSE BEGIN
+          where:=where+'(extension="'+ext+'")';
+        END;
+      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;
+    header_pc,header_mac:Boolean;
+  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));
+    header_pc:=True;
+    header_mac:=True;
+    FOR i:=0 TO High(dat_header.Ident) DO BEGIN
+      IF dat_header.Ident[i]<>header_ident1_pc[i] THEN BEGIN
+        header_pc:=False;
+      END;
+      IF dat_header.Ident[i]<>header_ident1_mac[i] THEN BEGIN
+        header_mac:=False;
+      END;
+    END;
+    IF NOT (header_pc OR header_mac) THEN BEGIN
+      Result:=False;
+      Exit;
+    END ELSE BEGIN
+      IF (header_pc AND NOT header_mac) THEN
+        dat_os_mac:=False
+      ELSE
+        IF (NOT header_pc AND header_mac) THEN
+          dat_os_mac:=True
+        ELSE BEGIN
+          Result:=False;
+          Exit;
+        END;
+    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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),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)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      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 LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+  VAR
+    i:Byte;
+    raw_info:TRawInfo;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      raw_info:=GetRawInfo(fileid,dat_offset);
+      LoadRawFile(fileid,dat_offset,raw_info.raw_addr,raw_info.raw_size,raw_info.loc_sep,target);
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Result:=True;
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT rawinfo.loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenReadWrite)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),fmOpenReadWrite);
+      filestream.Seek(rawinfo.raw_addr,soFromBeginning);
+      filestream.Write(target^,rawinfo.raw_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;
+    rawlist:TRawList;
+  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
+        rawlist:=GetRawList(fileid);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR i:=0 TO High(rawlist) DO BEGIN
+            ExportRawFile(fileid,rawlist[i].src_offset,path+'\'+GetWinFileName(filename));
+          END;
+        END;
+      END;
+    END;
+  END;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringList;
+  VAR
+    start,len:Word;
+  BEGIN
+    SetLength(Result, 0);
+    start:=1;
+    WHILE PosEx(delimiter,_string,start)>0 DO BEGIN
+      len:=PosEx(delimiter,_string,start)-start;
+      SetLength(Result, Length(Result)+1);
+      Result[High(Result)]:=MidStr(_string,start,len);
+      start:=start+len+1;
+    END;
+    SetLength(Result, Length(Result)+1);
+    Result[High(Result)]:=MidStr(_string,start,Length(_string)-start+1);
+  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.28a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.28a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,114 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.28a';
+  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;
+
+  TRawInfo=RECORD
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+    loc_sep:Boolean;
+  END;
+  TRawList=Array OF TRawInfo;
+
+VAR
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_os_mac:Boolean=False;
+  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_pc: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_ident1_mac:Array[0..$13] OF Byte=
+      ($61,$30,$C1,$23,$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.28a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.28a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,218 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, Dialogs, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset: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, Unit9_data_structures;
+
+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;
+
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    SetLength(data, GetRawInfo(fileid, dat_offset).raw_size);
+    LoadRawFileByIDOffset(fileid,dat_offset,@data[0]);
+    IF FileExists(filename+'.raw0x'+IntToHex(dat_offset,8)) THEN BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd);
+    END ELSE BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),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,$44,rawpos,Length(data),False,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.28a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.28a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.28a/src/Unit5_preview.dfm	(revision 8)
@@ -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.28a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.28a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit5_preview.pas	(revision 8)
@@ -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.28a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.28a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,406 @@
+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;
+  VAR
+    img_addr:LongWord;
+  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);
+    IF NOT dat_os_mac THEN
+      LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr)
+    ELSE
+      LoadDatFilePart(fileid,$A0,SizeOf(img_addr),@img_addr);
+
+    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);
+
+    IF NOT dat_os_mac THEN
+      LoadRawFile(fileid,$9C,img_addr,Result.datasize,dat_os_mac,@Result.imgdata[0])
+    ELSE
+      LoadRawFile(fileid,$A0,img_addr,Result.datasize,dat_os_mac,@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.28a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.28a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.28a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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 = 'MIP Mapping'
+      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.28a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.28a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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.28a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.28a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.28a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,302 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 423
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  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 = []
+      OnKeyUp = hexKeyUp
+      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
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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.28a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.28a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,747 @@
+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, Math;
+
+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 hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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, Unit13_rawedit;
+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]);
+      11: Result:='0x'+IntToHex(GetRawInfo(fileid,offset).raw_addr,8);
+      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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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;
+    i:LongWord;
+  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);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        IF GetRawInfo(fileid,offset).raw_size>0 THEN BEGIN
+        //edit_filtername.Text:=IntToStr(GetRawInfo(fileid,offset).raw_size);
+          IF Form1.open_child('rawedit') THEN BEGIN
+            TForm13(Form1.ActiveMDIChild).LoadRaw(GetRawInfo(fileid,offset));
+          END;
+        END;
+        {LOAD RAW-EDITOR}
+      END;
+    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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.28a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.28a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.28a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,474 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, ABSMain, DB, ABSDecUtil, Classes, Unit3_data, Dialogs, StrUtils;
+
+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; 11: raw-addr; 10000+: string[0+]
+      description:String;
+    END;
+  Tstructure_info=RECORD
+      extension:String;
+      typedesc:String;
+      entries:Array OF Tstructure_entry;
+    END;
+  Tstructures=Array OF Tstructure_info;
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+
+VAR
+  structure_infos:Tstructures;
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+
+PROCEDURE LoadStructureDefinitions(defdir:String);
+
+
+IMPLEMENTATION
+USES Unit2_functions;
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      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';
+      11: Result:='Raw-Address';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  VAR
+    i:LongWord;
+    raw_list:TRawList;
+  BEGIN
+    raw_list:=GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    FOR i:=0 TO High(raw_list) DO BEGIN
+      IF raw_list[i].src_offset=dat_offset THEN BEGIN
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Result.loc_sep:=raw_list[i].loc_sep;
+        Break;
+      END;
+    END;
+  END;
+
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+  VAR
+    i:LongWord;
+    Query:TABSQuery;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=0 TO High(RawListHandlers) DO
+        IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN
+          IF RawListHandlers[i].needed THEN BEGIN
+            Result:=RawListHandlers[i].Handler(fileid);
+            Break;
+          END ELSE
+            Break;
+    END ELSE BEGIN
+      SetLength(Result,0);
+      Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i].src_id:=fileid;
+          Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger;
+          Result[i].raw_addr:=0;
+          Result[i].raw_size:=Query.FieldByName('size').AsInteger;
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*4;
+        LoadDatFilePart(fileid,$20+i*4,4,@link);
+        Result[i].raw_addr:=link;
+        Result[i].raw_size:=0{????????????????????????????????};
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION AKVA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*$74+$24;
+        LoadDatFilePart(fileid,$20+i*$74+$24,4,@link);
+        Result[i].raw_addr:=link;
+        LoadDatFilePart(fileid,$20+i*$74+$28,4,@link);
+        Result[i].raw_size:=link;
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$0C,4,@link);
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$40,4,@datasize);
+    LoadDatFilePart(fileid,$44,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$44;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,link:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    LoadDatFilePart(fileid,$18,4,@baselink);
+    LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      LoadDatFilePart(fileid,$20+(links-1)*4,4,@link);
+      SetLength(data,link+1024);
+      LoadRawFile(fileid,$1C,baselink,link+1024,False,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[link+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=link+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    LoadDatFilePart(fileid,$182,1,@tempb);
+    LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    LoadDatFilePart(fileid,$183,1,@tempb);
+    LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    LoadDatFilePart(fileid,$184,1,@tempb);
+    LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    LoadDatFilePart(fileid,$185,1,@tempb);
+    LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    LoadDatFilePart(fileid,$186,1,@tempb);
+    LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    LoadDatFilePart(fileid,$187,1,@tempb);
+    LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    LoadDatFilePart(fileid,$154,2,@tempw);
+    LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    LoadDatFilePart(fileid,$138,4,@templ);
+    LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link_pc:LongWord;
+    link_mac:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    LoadDatFilePart(fileid,$9C,4,@link_pc);
+    LoadDatFilePart(fileid,$A0,4,@link_mac);
+    CASE storetype OF
+      0,1,2: datasize:=x*y*2;
+      8: datasize:=x*y*4;
+      9: datasize:=x*y DIV 2;
+    END;
+    SetLength(Result,1);
+    IF NOT dat_os_mac THEN BEGIN
+      Result[0].src_offset:=$9C;
+      Result[0].raw_addr:=link_pc
+    END ELSE BEGIN
+      Result[0].src_offset:=$A0;
+      Result[0].raw_addr:=link_mac;
+    END;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  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;
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+PROCEDURE LoadStructureDefinitionFile(filename:String);
+  VAR
+    temps:String;
+    deffile:Text;
+    ext:String;
+    fields:TStringList;
+    fieldname:String;
+    fieldoffset:LongWord;
+    fieldtype:Word;
+    fielddesc:String;
+  BEGIN
+    ext:=MidStr(ExtractFileName(filename),1,4);
+    AssignFile(deffile,filename);
+    Reset(deffile);
+    IF NOT EoF(deffile) THEN BEGIN
+      ReadLn(deffile,temps);
+      AddExtension(ext,temps);
+      WHILE NOT EoF(deffile) DO BEGIN
+        ReadLn(deffile,temps);
+        fields:=Explode(temps,#9);
+        IF (Length(fields)=3) OR (Length(fields)=4) THEN BEGIN
+          fieldname:=fields[0];
+          fieldoffset:=HexToLong(fields[1]);
+          fieldtype:=StrToInt(fields[2]);
+          IF Length(fields)=4 THEN
+            fielddesc:=fields[3]
+          ELSE
+            fielddesc:='';
+//          ShowMessage(fieldname+' - '+IntToHex(fieldoffset,4)+' - '+IntToStr(fieldtype)+' - '+fielddesc);
+          AddEntry(ext,fieldname,fieldoffset,fieldtype,fielddesc);
+        END;
+      END;
+    END;
+    CloseFile(deffile);
+  END;
+
+PROCEDURE LoadStructureDefinitions(defdir:String);
+  VAR
+    SR:TSearchRec;
+  BEGIN
+    IF DirectoryExists(defdir) THEN BEGIN
+      IF FindFirst(defdir+'\*.txt', faAnyFile, SR)=0 THEN BEGIN
+        REPEAT
+          IF (SR.Attr AND faDirectory) <> faDirectory THEN BEGIN
+            LoadStructureDefinitionFile(defdir+'\'+SR.Name);
+          END;
+        UNTIL FindNext(SR)<>0;
+      END;
+      FindClose(SR);
+    END;
+  END;
+
+BEGIN
+//  InsertRawListHandler('AGDB',True,AGDB);
+  InsertRawListHandler('AKVA',True,AKVA);
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.28a/todo.txt
===================================================================
--- /oup/releases/0.28a/todo.txt	(revision 8)
+++ /oup/releases/0.28a/todo.txt	(revision 8)
@@ -0,0 +1,157 @@
+Unit10 unabhängig, funktionsweise wiederherstellen
+Schreibt auch die dat_files[] etc
+Benutzt die *globalen* dat_stream/raw_stream und keine MemCopy
+
+
+ValueViewer: Offset
+
+TXMPReplace: Zugriff über Unit2
+
+
+SELECT [src_id],MIN(datfiles.[name]),SUM(rawmap.[size]) FROM rawmap INNER  JOIN datfiles ON datfiles.[id]=[src_id] GROUP BY [src_id] ORDER BY [src_id] ASC
+
+Extrahier-Ordner-Option (mit Platzhalter für .dat-Name)
+
+-HELP.hlp
+-About
+
+-BinEdit: Zusatzfunktionen wie: Suche, 
+-BinEdit: Bild/Menu/Button irgendwas zum speichern
+
+-Extractor: Wohin?
+
+-FileCompare: Ergebnis=Tabelle, jede Zeile eine differenz-addresse, spalten = werte an addr. für compared files
+
+-TXMP-Replace: MultiReplace
+
+-Move-Freischalter (Mindestlvl eingabe)
+
+-Löschen einer Datei auf die gelinkt wird: Liste der Links und sicherheitsfrage
+
+-Filebox-Context: Extract etc
+
+-DAT geladen -> Meldung oder sogar "what to do next?"
+-SSG: Levels extrahieren?
+-Pierre: Wie Char-Anims, Char-Models, Levels extrahieren?
+-Language-Files?
+-STRG+C auf Dateilisten etc für kopieren des Namens
+
+-REPACKING: testen lvl0: 690-collisions.txmp einbauen, script: collisions-zeug
+
+#################################################################
+##########                 File-Types                  ##########
+#################################################################
+(3CLA)
+ABNA
+AGDB
+AGQC
+AGQG
+(AGQM)
+AGQR
+AISA
+AITR
+(AIWA)
+AKAA
+AKBA
+AKBP
+AKDA
+AKEV
+AKOT
+AKVA
+BINA
+CBPI
+CBPM
+CONS
+CRSA
+DOOR
+DPge
+(EDIA)
+ENVP
+FILM
+(FXLR)
+(GMAN)
+HPge
+IDXA
+IGHH
+IGPA
+IGPG
+IGSA
+IGSt
+Impt
+IPge
+KeyI
+M3GA
+M3GM
+(M3TA)
+Mtrl
+(NMSA)
+OBAN
+OBDC
+(OBLS)
+OBOA
+OFGA
+ONCC
+ONCP
+ONCV
+ONFA
+ONGS
+ONIA
+ONLD
+ONLV
+ONMA
+ONOA
+ONSA
+ONSK
+ONTA
+ONVL
+ONWC
+OPge
+OSBD
+OTIT
+OTLF
+PLEA
+PNTA
+PSpc
+PSpL
+PSUI
+QTNA
+(QUDA)
+SNDD
+StNA
+SUBT
+(TMFA)
+(TMRA)
+TRAC
+TRAM
+TRAS
+TRBS
+TRCM
+(TRFT)
+TRGA
+TRGE
+TRIA
+TRIG
+TRMA
+TRSC
+TRTA
+TSFF
+TSFL
+TSFT
+TSGA
+TStr
+TURR
+TXAN
+TXCA
+TXMA
+TXMB
+TXMP
+(TXPC)
+TxtC
+(UUEA)
+(UVDL)
+VCRA
+WMCL
+WMDD
+WMM_
+WMMB
+WPge
Index: /oup/releases/0.29a/StructDefs/AISA.txt
===================================================================
--- /oup/releases/0.29a/StructDefs/AISA.txt	(revision 8)
+++ /oup/releases/0.29a/StructDefs/AISA.txt	(revision 8)
@@ -0,0 +1,8 @@
+AI Character Setup Array
+
+File ID	$00	12
+Level ID	$04	4
+Unused	$08	1022
+Packages	$1E	2
+*AIs#$20#$1E#2#352
+Intro func	$50	10032
Index: /oup/releases/0.29a/StructDefs/ONCC.txt
===================================================================
--- /oup/releases/0.29a/StructDefs/ONCC.txt	(revision 8)
+++ /oup/releases/0.29a/StructDefs/ONCC.txt	(revision 8)
@@ -0,0 +1,58 @@
+Oni character class
+TXMP link	$28	12	Shadow texture
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use an hypo
+Hurt light sound	$98	10032	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	10032	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	10032	Reference to an OSBD file of level 0
+Death sound	$F8	10032	Reference to an OSBD file of level 0
+Taunt sound query	$2B0	10	00 = not used; 64 = used
+"Whos there?" sound query	$2B1	10	00 = not used; 64 = used
+"I see you" sound query	$2B2	10	00 = not used; 64 = used
+"You lose" sound query	$2B3	10	00 = not used; 64 = used
+"Where are you?" sound query	$2B4	10	00 = not used; 64 = used
+"Why is this happenung?" sound query	$2B5	10	00 = not used; 64 = used
+Superpunch sound query	$2B6	10	00 = not used; 64 = used
+Superkick sound query	$2B7	10	00 = not used; 64 = used
+Super3 sound query	$2B8	10	00 = not used; 64 = used
+Super4 sound query	$2B9	10	00 = not used; 64 = used
+Taunt sound	$2BC	10032	Reference to a SNDD file of level 0
+"Whos there?" sound	$2DC	10032	Reference to a SNDD file of level 0
+"I see you" sound	$2FC	10032	Reference to a SNDD file of level 0
+"You lose" sound	$31C	10032	Reference to a SNDD file of level 0
+"Where are you?" sound	$33C	10032	Reference to a SNDD file of level 0
+"Why is this happenung?" sound	$35C	10032	Reference to a SNDD file of level 0
+Superpunch sound	$37C	10032	Reference to a SNDD file of level 0
+Superkick sound	$39C	10032	Reference to a SNDD file of level 0
+Super3 sound	$3BC	10032	Reference to a SNDD file of level 0
+Super4 sound	$3DC	10032	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV link	$434	12	Character varient link
+ONCP link	$438	12	Character particle array link; useless?
+ONIA link	$43C	12	Character impact array link; useless?
+Unknown	$444	10016	Maybe the weight of the character?
+Footstep walk impact	$454	10128	Reference to the a Impt file of level 0
+Footstep run impact	$4D6	10128	Reference to the a Impt file of level 0
+Footstep crouch impact	$558	10128	Reference to the a Impt file of level 0
+Fall slide impact	$5DA	10128	Reference to the a Impt file of level 0
+Fall land impact	$65C	10128	Reference to the a Impt file of level 0
+Fall land hard impact	$6DE	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$760	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$7E2	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$864	10128	Reference to the a Impt file of level 0
+Footstep turn impact	$8E6	10128	Reference to the a Impt file of level 0
+Footstep run start impact	$968	10128	Reference to the a Impt file of level 0
+Footstep single step impact	$9EA	10128	Reference to the a Impt file of level 0
+Footstep run stop impact	$A6C	10128	Reference to the a Impt file of level 0
+Footstep walk stop impact	$AEE	10128	Reference to the a Impt file of level 0
+Footstep run sprint impact	$B70	10128	Reference to the a Impt file of level 0
+Unknown	$BF4	10064	special death particles; only the mad bomber use it
+TRBS link	$C3C	8	Body set link
+TRMA link	$C40	8	Texture map array link
+CBPM link	$C44	8	Body part material link
+CBPI link	$C48	8	Body part impact link
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC link	$C88	8	Animation collection link
+TRSC link	$C8C	8	Screen (aiming) collection link
Index: /oup/releases/0.29a/StructDefs/SUBT.txt
===================================================================
--- /oup/releases/0.29a/StructDefs/SUBT.txt	(revision 8)
+++ /oup/releases/0.29a/StructDefs/SUBT.txt	(revision 8)
@@ -0,0 +1,5 @@
+Subtitles
+ID	$00	4	ID of this file
+LevelID	$04	8	ID of the level this file is in
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Subtitle count	$1C	4	Number of subtitles in this file
Index: /oup/releases/0.29a/StructDefs/TRAM.txt
===================================================================
--- /oup/releases/0.29a/StructDefs/TRAM.txt	(revision 8)
+++ /oup/releases/0.29a/StructDefs/TRAM.txt	(revision 8)
@@ -0,0 +1,49 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	8	Flags; It seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	8	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	8	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	2	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	10016	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	6	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
Index: /oup/releases/0.29a/StructDefs/TXAN.txt
===================================================================
--- /oup/releases/0.29a/StructDefs/TXAN.txt	(revision 8)
+++ /oup/releases/0.29a/StructDefs/TXAN.txt	(revision 8)
@@ -0,0 +1,14 @@
+Texture Animation
+
+File ID	$00	12	File ID of this file
+Level Number	$04	4
+Unused	$08	1012
+
+Loop speed	$14	2
+Unknown	$16	2
+Unknown	$18	2
+Unused	$1A	1002
+Number of images	$1C	4
+
+*Packages#$20#$1C#4#4
+Image	$0	12
Index: /oup/releases/0.29a/StructDefs/TXMP.txt
===================================================================
--- /oup/releases/0.29a/StructDefs/TXMP.txt	(revision 8)
+++ /oup/releases/0.29a/StructDefs/TXMP.txt	(revision 8)
@@ -0,0 +1,13 @@
+Texture
+ID	$00	12	ID of this file
+LevelID	$04	8	ID of the level this file is in
+FileName	$08	10128	
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	12	Link to the TXAN-file (if this TXMP is the first image of an animation)
+TXMP-Link	$98	12	Link to another TXMP-file
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
Index: /oup/releases/0.29a/blubb.txt
===================================================================
--- /oup/releases/0.29a/blubb.txt	(revision 8)
+++ /oup/releases/0.29a/blubb.txt	(revision 8)
@@ -0,0 +1,6 @@
+___FILEINDEX___.txt
+
+
+TXMP:
+MipMapping: Bit0=an/aus
+ColorDepth: Bit0=??AnimationPic??, Bit1=shade vertex, Bit2=transparency, Bit4=16bit, Bit5=32bit
Index: /oup/releases/0.29a/changelog.txt
===================================================================
--- /oup/releases/0.29a/changelog.txt	(revision 8)
+++ /oup/releases/0.29a/changelog.txt	(revision 8)
@@ -0,0 +1,88 @@
+OniUnPacker v0.29a
+------------------
++New StructureViewer
++New StructureTypes: 12=.dat-file-ID, 13..16=SignedInteger, 1000..9999=Unused data
++Dynamic Structures (look at TXAN-files or AISA-files for examples)
+
+OniUnPacker v0.28a
+------------------
++StructureDefinitions as separate txt-files
++Minor bugfixes
++Ctrl+C for Hex-fields
+
+OniUnPacker v0.27a
+------------------
++Added MAC-file support
++Added StructureDefs for ONCCs / TRAMs (thanks to SSG)
+
+OniUnPacker v0.26a
+------------------
++Fixed some bugs again ;)
+
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.29a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.29a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.29a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,184 @@
+﻿<?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 Name="UnitInitSeq">True</Compiler>
+			<Compiler Name="LocalPInvoke">True</Compiler>
+			<Compiler Name="CodePage"></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 Name="GenerateHpps">False</Linker>
+		</Linker>
+		<Directories>
+			<Directories Name="OutputDir">exe</Directories>
+			<Directories Name="UnitOutputDir">dcu</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 Name="Debug Symbols Search Path"></Parameters>
+			<Parameters Name="LoadAllSymbols">True</Parameters>
+			<Parameters Name="LoadUnspecifiedSymbols">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>
+		<Language>
+			<Language Name="ActiveLang"></Language>
+			<Language Name="ProjectLang">$00000000</Language>
+			<Language Name="RootDir"></Language>
+		</Language>  
+    <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.29a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.29a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.29a/src/OniUnPacker.cfg	(revision 8)
@@ -0,0 +1,40 @@
+-$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
+-E"exe"
+-N0"dcu"
+-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.29a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.29a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.29a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,31 @@
+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},
+  Unit13_rawedit in 'Unit13_rawedit.pas' {Form13},
+  Unit14_settings in 'Unit14_settings.pas' {Form14},
+  ftypesAPI in 'TFileTypeRegistration\ftypesAPI.pas';
+
+{$R *.res}
+{$R icon2.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.CreateForm(TForm12, Form12);
+  Application.CreateForm(TForm14, Form14);
+  Application.Run;
+END.
Index: /oup/releases/0.29a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.29a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.29a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,952 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit9_data_structures;
+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;
+  raw_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.CreateLevel(source,target:String);
+  VAR
+    i:LongWord;
+  BEGIN
+  END;
+
+PROCEDURE TForm10.CreateDatabase(source,target:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+  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:=target;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=loaded_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:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    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;
+
+        rawlist:=GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              mem:=TMemoryStream.Create;
+              filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+              filestream.Seek(rawlist[j].raw_addr,soFromBeginning);
+              mem.CopyFrom(filestream,rawlist[j].raw_size);
+              filestream.Free;
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") );';
+              Query.ExecSQL;
+              mem.Free;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        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 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 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 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 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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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',False,NIL);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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.29a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+object Form11: TForm11
+  Left = 0
+  Top = 0
+  Caption = 'Extractor'
+  ClientHeight = 398
+  ClientWidth = 487
+  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
+      MultiSelect = True
+      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.29a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.29a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit11_extractor.pas	(revision 8)
@@ -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(GetFilesCount)+')');
+    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(GetFileIDByName(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+            END ELSE BEGIN
+              ExportFile(GetFileIDByName(list.Items.Strings[list.ItemIndex]),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(GetFileIDByName(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+          END ELSE BEGIN
+            ExportFile(GetFileIDByName(list.Items.Strings[list.ItemIndex]),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.29a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.29a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.29a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,119 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      13..16: BEGIN
+              Exit;
+              edit_new.EditType:=etInteger;
+              edit_new.LimitCheck:=True;
+              edit_new.Max:=Int((Power(256,datatype-13)) / 2)-1;
+              edit_new.Min:=1-Int((Power(256,datatype-13)) / 2)-1;
+            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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.29a/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,324 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  ClientHeight = 640
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = []
+      OnKeyUp = hexKeyUp
+      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 = 600
+      Width = 483
+      Height = 40
+      Align = alBottom
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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 = 374
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 337
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 352
+        Width = 146
+        Height = 88
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        OnResize = panel_extensionResize
+        object lbl_filter: TLabel
+          Left = 2
+          Top = 46
+          Width = 100
+          Height = 17
+          AutoSize = False
+          Caption = 'Filter by &extension:'
+          FocusControl = combo_extension
+        end
+        object combo_extension: TComboBox
+          Left = 2
+          Top = 60
+          Width = 145
+          Height = 21
+          Style = csDropDownList
+          DropDownCount = 12
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Tahoma'
+          Font.Style = []
+          ItemHeight = 0
+          ParentFont = False
+          Sorted = True
+          TabOrder = 2
+          OnClick = combo_extensionClick
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.29a/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.29a/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,809 @@
+UNIT Unit13_rawedit;
+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, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+  dat_offset:LongWord;
+  fileid_opened,dat_offset_opened:LongWord;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    IF list_offset.Count=0 THEN BEGIN
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF GetFileIDByName(list.Items.Strings[i])=raw_info.src_id THEN BEGIN
+          list.ItemIndex:=i;
+          listClick(Self);
+          Break;
+        END;
+      END;
+      FOR i:=0 TO list_offset.Count-1 DO BEGIN
+        IF MidStr(list_offset.Items.Strings[i],3,8)=IntToHex(raw_info.src_offset,8) THEN BEGIN
+          list_offset.ItemIndex:=i;
+          Break;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    LoadRawFilebyIDOffset(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+    count:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=GetExtensionsList;
+    FOR i:=0 TO High(RawListHandlers) DO BEGIN
+      count:=Length(GetFilesList(RawListHandlers[i].Ext,'',True));
+      combo_extension.Items.Add(RawListHandlers[i].ext+' ('+IntToStr(count)+')');
+    END;
+//    FOR i:=0 TO High(exts) DO
+//      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm13.LoadFileNames;
+  VAR
+    Extension:String;
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN BEGIN
+      Extension:='';
+      FOR i:=0 TO High(RawListHandlers) DO BEGIN
+        IF Length(Extension)>0 THEN Extension:=Extension+',';
+        Extension:=Extension+RawListHandlers[i].Ext;
+      END;
+    END;
+
+    files:=GetFilesList(extension,pattern,TRUE);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    list_offset.Enabled:=True;
+    IF GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,8)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,8));
+    LoadRaw(GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of 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;
+          UpdateRawFile(GetRawInfo(fileid_opened,dat_offset_opened),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm13.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  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
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.29a/src/Unit14_settings.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit14_settings.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit14_settings.dfm	(revision 8)
@@ -0,0 +1,75 @@
+object Form14: TForm14
+  Left = 0
+  Top = 0
+  BorderStyle = bsToolWindow
+  Caption = 'Settings'
+  ClientHeight = 350
+  ClientWidth = 250
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object check_filesashex: TCheckBox
+    Left = 8
+    Top = 8
+    Width = 145
+    Height = 17
+    Caption = 'Show filenumbers as Hex'
+    TabOrder = 0
+  end
+  object btn_ok: TButton
+    Left = 8
+    Top = 319
+    Width = 57
+    Height = 23
+    Caption = 'OK'
+    Default = True
+    TabOrder = 1
+    OnClick = btn_okClick
+  end
+  object btn_cancel: TButton
+    Left = 120
+    Top = 319
+    Width = 57
+    Height = 23
+    Cancel = True
+    Caption = 'Cancel'
+    TabOrder = 2
+    OnClick = btn_cancelClick
+  end
+  object btn_register_oldb: TButton
+    Left = 8
+    Top = 128
+    Width = 169
+    Height = 25
+    Caption = 'Register .oldb files with OUP'
+    TabOrder = 3
+    OnClick = btn_register_oldbClick
+  end
+  object btn_register_opf: TButton
+    Left = 8
+    Top = 159
+    Width = 169
+    Height = 25
+    Caption = 'Register .opf files with OUP'
+    TabOrder = 4
+    OnClick = btn_register_opfClick
+  end
+  object btn_register_dat: TButton
+    Left = 8
+    Top = 97
+    Width = 169
+    Height = 25
+    Caption = 'Register .dat files with OUP'
+    TabOrder = 5
+    OnClick = btn_register_datClick
+  end
+end
Index: /oup/releases/0.29a/src/Unit14_settings.pas
===================================================================
--- /oup/releases/0.29a/src/Unit14_settings.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit14_settings.pas	(revision 8)
@@ -0,0 +1,155 @@
+unit Unit14_settings;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils;
+
+type
+  TForm14 = class(TForm)
+    check_filesashex: TCheckBox;
+    btn_ok: TButton;
+    btn_cancel: TButton;
+    btn_register_oldb: TButton;
+    btn_register_opf: TButton;
+    btn_register_dat: TButton;
+    procedure btn_register_opfClick(Sender: TObject);
+    procedure btn_register_oldbClick(Sender: TObject);
+    procedure btn_register_datClick(Sender: TObject);
+    procedure btn_cancelClick(Sender: TObject);
+    procedure btn_okClick(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormShow(Sender: TObject);
+    function RegisterExtension(ext:String):Integer;
+  private
+  public
+  end;
+
+var
+  Form14: TForm14;
+
+implementation
+{$R *.dfm}
+uses
+  Unit1_main, Unit3_data, ftypesAPI;
+
+function ExtensionRegistered(ext:String; var RegisteredAs:String):Boolean;
+  var
+    ftr:TFileTypeRegistration;
+  begin
+    ftr:=TFileTypeRegistration.Create;
+    if(ftr <> nil) then begin
+      try
+        RegisteredAs:=ftr.GetInternalKey(ext);
+        if RegisteredAs<>'' then
+          Result:=True
+        else
+          Result:=False;
+      finally
+        ftr.Free;
+      end;
+    end;
+  end;
+
+function TForm14.RegisterExtension(ext:String):Integer;
+  var
+    ftr:TFileTypeRegistration;
+    temps:String;
+    warnmsg:String;
+  begin
+    Result:=-1;
+    if ExtensionRegistered(ext,temps) then begin
+      if temps<>'ONI'+ext then begin
+        warnmsg:=ext+'-files are not registered to OUP but as "'+temps+'"-files.'+#13+#10+
+                 'Do you really want to unregister'+ext+'-files?';
+        if MessageBox(Self.Handle, PChar(warnmsg),PChar('Warning'),MB_YESNO)=ID_NO then
+          Exit;
+      end;
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then
+        try
+          if not ftr.UnregisterExtension(ext) then
+            ShowMessage('Could not unregister '+ext+'-files')
+          else
+            Result:=2;
+        finally
+          ftr.Free;
+        end;
+    end else begin
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then begin
+        try
+          if ftr.RegisterType(ext,'ONI'+ext,'ONI '+ext+'-file',Application.EXEname+',1') then begin
+            ftr.AddHandler('open','"'+Application.EXEname+'" '+MidStr(ext,2,Length(ext)-1)+' "%1"');
+            ftr.SetDefaultHandler;
+            Result:=1;
+          end;
+        finally
+          ftr.Free;
+        end;
+      end;
+    end;
+  end;
+
+procedure TForm14.btn_cancelClick(Sender: TObject);
+  begin
+    Self.Close;
+  end;
+
+procedure TForm14.btn_okClick(Sender: TObject);
+  begin
+    AppSettings.FilenumbersAsHex:=check_filesashex.Checked;
+    Self.Close;
+  end;
+
+procedure TForm14.btn_register_datClick(Sender: TObject);
+  begin
+    case RegisterExtension('.dat') of
+      2: btn_register_dat.Caption:='Register .dat files with OUP';
+      1: btn_register_dat.Caption:='Unregister .dat files';
+    end;
+  end;
+
+procedure TForm14.btn_register_oldbClick(Sender: TObject);
+  begin
+    case RegisterExtension('.oldb') of
+      2: btn_register_oldb.Caption:='Register .oldb files with OUP';
+      1: btn_register_oldb.Caption:='Unregister .oldb files';
+    end;
+  end;
+
+procedure TForm14.btn_register_opfClick(Sender: TObject);
+  begin
+    case RegisterExtension('.opf') of
+      2: btn_register_opf.Caption:='Register .opf files with OUP';
+      1: btn_register_opf.Caption:='Unregister .opf files';
+    end;
+  end;
+
+procedure TForm14.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  begin
+    CanClose:=False;
+    Self.Visible:=False;
+    Form1.Enabled:=True;
+    Form1.SetFocus;
+  end;
+
+procedure TForm14.FormShow(Sender: TObject);
+  var
+    temps:String;
+  begin
+    if ExtensionRegistered('.dat',temps) then
+      btn_register_dat.Caption:='Unregister .dat files'
+    else
+      btn_register_dat.Caption:='Register .dat files with OUP';
+    if ExtensionRegistered('.oldb',temps) then
+      btn_register_oldb.Caption:='Unregister .oldb files'
+    else
+      btn_register_oldb.Caption:='Register .oldb files with OUP';
+    if ExtensionRegistered('.opf',temps) then
+      btn_register_opf.Caption:='Unregister .opf files'
+    else
+      btn_register_opf.Caption:='Register .opf files with OUP';
+    check_filesashex.Checked:=AppSettings.FilenumbersAsHex;
+  end;
+
+end.
Index: /oup/releases/0.29a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,186 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  Caption = 'Form1'
+  ClientHeight = 506
+  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 = 489
+    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 = 469
+    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 ClosefileDB1: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = ClosefileDB1Click
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_settings: TMenuItem
+        Caption = 'Se&ttings...'
+        OnClick = menu_settingsClick
+      end
+      object menu_sep4: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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.29a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.29a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,519 @@
+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, Unit9_data_structures,
+  Unit10_leveldb, Unit4_exporters, Unit14_settings,
+  Unit5_preview, Unit7_txmpreplace, Unit8_binedit, Unit11_extractor, Unit13_rawedit;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    ClosefileDB1: TMenuItem;
+    menu_sep4: TMenuItem;
+    menu_settings: TMenuItem;
+    PROCEDURE menu_settingsClick(Sender: TObject);
+    PROCEDURE ClosefileDB1Click(Sender: TObject);
+    PROCEDURE menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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;
+//    LoadStructureDefinitions(ExtractFilepath(Application.EXEname)+'\StructDefs');
+
+    IF MidStr(ParamStr(1),1,3)='opf' THEN BEGIN
+      ShowMessage('Load OPF-File: '+ParamStr(2));
+    END ELSE IF MidStr(ParamStr(1),1,4)='oldb' THEN BEGIN
+      OpenDatabase(ParamStr(2));
+      IF opened_state=opened_db THEN BEGIN
+        menu_tools.Enabled:=True;
+        menu_convert.Enabled:=False;
+        statbar.Panels.Items[0].Text:='OLDB loaded: '+ParamStr(2);
+        statbar.Panels.Items[1].Text:='Files: '+IntToStr(GetFilesCount);
+        statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(GetExtensionsList));
+      END ELSE BEGIN
+        menu_tools.Enabled:=False;
+        menu_convert.Enabled:=True;
+      END;
+    END ELSE IF MidStr(ParamStr(1),1,3)='dat' THEN BEGIN
+      IF LoadDatInfos(ParamStr(2)) THEN BEGIN
+        Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(ParamStr(2))+')';
+        statbar.Panels.Items[0].Text:='.dat loaded: '+ParamStr(2);
+        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:=False;
+      END ELSE BEGIN
+        menu_convert.Enabled:=True;
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+        END ELSE BEGIN
+          menu_convert.Enabled:=True;
+          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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+          statbar.Panels.Items[0].Text:='OLDB loaded: '+opend.FileName;
+          statbar.Panels.Items[1].Text:='Files: '+IntToStr(GetFilesCount);
+          statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(GetExtensionsList));
+        END ELSE BEGIN
+          menu_tools.Enabled:=False;
+          menu_convert.Enabled:=True;
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.ClosefileDB1Click(Sender: TObject);
+  BEGIN
+    menu_windows_closeallClick(Form1);
+    IF Length(tablist)=0 THEN BEGIN
+      IF opened_state=opened_db THEN CloseDatabase;
+      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: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+PROCEDURE TForm1.menu_settingsClick(Sender: TObject);
+  BEGIN
+    Form14.Visible:=True;
+    Self.Enabled:=False;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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;
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.29a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.29a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,683 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data, 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 GetFilesCount:LongWord;
+FUNCTION GetExtensionsList:TStringList;
+FUNCTION GetFileIDByName(name:String):LongWord;
+
+FUNCTION HexToLong(hex:String):LongWord;
+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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+FUNCTION LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; 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;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringList;
+
+
+IMPLEMENTATION
+USES Unit4_Exporters, Unit9_data_structures;
+
+VAR
+  Database:TABSDatabase;
+  Query:TABSQuery;
+
+TYPE
+  TValueSwitcher=Record
+    CASE IsFloat: Boolean OF
+      True: (ValueFloat:Single);
+      False: (ValueInt:LongWord);
+  END;
+
+FUNCTION NormalizeHexString(VAR hex:String):Boolean;
+  VAR
+    i:Byte;
+  BEGIN
+    IF hex[1]='$' THEN BEGIN
+      FOR i:=1 TO Length(hex)-1 DO BEGIN
+        hex[i]:=hex[i+1];
+      END;
+      SetLength(hex, Length(hex)-1);
+    END;
+    IF (hex[1]='0') AND (UpCase(hex[2])='X') THEN BEGIN
+      FOR i:=1 TO Length(hex)-2 DO BEGIN
+        hex[i]:=hex[i+2];
+      END;
+      SetLength(hex, Length(hex)-2);
+    END;
+    IF Length(hex)=0 THEN
+      Result:=False
+    ELSE
+      Result:=True;
+  END;
+
+FUNCTION HexToLong(hex:String):LongWord;
+  VAR
+    i:Byte;
+  BEGIN
+    IF NormalizeHexString(hex) THEN BEGIN
+      hex:=UpperCase(hex);
+      Result:=0;
+      FOR i:=1 TO Length(hex) DO BEGIN
+        Result:=Result SHL 4;
+        CASE hex[i] OF
+          '0'..'9': Result:=Result+Ord(hex[i])-48;
+          'A'..'F': Result:=Result+Ord(hex[i])-55;
+        ELSE
+          Result:=0;
+          Exit;
+        END;
+      END;
+    END ELSE BEGIN
+      Result:=0;
+    END;
+  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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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:=Query.FieldByName('size').AsInteger;
+        Result.FileType:=Query.FieldByName('contenttype').AsInteger;
+        Result.DatAddr:=0;
+        Result.opened:=False;
+      END;
+      Query.Close;
+    END;
+  END;
+
+FUNCTION GetFileIDByName(name:String):LongWord;
+  BEGIN
+    IF AppSettings.FilenumbersAsHex THEN
+      Result:=HexToLong(MidStr(name,1,4))
+    ELSE
+      Result:=StrToInt(MidStr(name,1,5));
+  END;
+
+FUNCTION GetFilesCount:LongWord;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=dat_header.Files;
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT Count(*) AS cnumber FROM datfiles;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        Result:=Query.FieldByName('cnumber').AsInteger;
+      END ELSE Result:=0;
+      Query.Close;
+    END;
+  END;
+
+FUNCTION GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringList;
+  VAR
+    i:LongWord;
+    where:String;
+    where_ext: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 (Pos(dat_files[i].Extension,ext)>0) ) 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);
+              IF AppSettings.FilenumbersAsHex THEN
+                Result[High(Result)]:=dat_files[i].FileNameHex
+              ELSE
+                Result[High(Result)]:=dat_files[i].FileName;
+            END;
+          END ELSE BEGIN
+            SetLength(Result,Length(Result)+1);
+            IF AppSettings.FilenumbersAsHex THEN
+              Result[High(Result)]:=dat_files[i].FileNameHex
+            ELSE
+              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 ';
+        IF Pos(',',ext)>0 THEN BEGIN
+          i:=1;
+          where_ext:='';
+          WHILE i<Length(ext) DO BEGIN
+            IF Length(where_ext)>0 THEN where_ext:=where_ext+' OR ';
+            where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")';
+            i:=i+5;
+          END;
+          where:=where+'('+where_ext+')';
+        END ELSE BEGIN
+          where:=where+'(extension="'+ext+'")';
+        END;
+      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;
+    header_pc,header_mac:Boolean;
+  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));
+    header_pc:=True;
+    header_mac:=True;
+    FOR i:=0 TO High(dat_header.Ident) DO BEGIN
+      IF dat_header.Ident[i]<>header_ident1_pc[i] THEN BEGIN
+        header_pc:=False;
+      END;
+      IF dat_header.Ident[i]<>header_ident1_mac[i] THEN BEGIN
+        header_mac:=False;
+      END;
+    END;
+    IF NOT (header_pc OR header_mac) THEN BEGIN
+      Result:=False;
+      Exit;
+    END ELSE BEGIN
+      IF (header_pc AND NOT header_mac) THEN
+        dat_os_mac:=False
+      ELSE
+        IF (NOT header_pc AND header_mac) THEN
+          dat_os_mac:=True
+        ELSE BEGIN
+          Result:=False;
+          Exit;
+        END;
+    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;
+      dat_files[i].FileNameHex:=IntToHex(i,4)+'-'+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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),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)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      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 LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+  VAR
+    i:Byte;
+    raw_info:TRawInfo;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      raw_info:=GetRawInfo(fileid,dat_offset);
+      LoadRawFile(fileid,dat_offset,raw_info.raw_addr,raw_info.raw_size,raw_info.loc_sep,target);
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Result:=True;
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT rawinfo.loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenReadWrite)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),fmOpenReadWrite);
+      filestream.Seek(rawinfo.raw_addr,soFromBeginning);
+      filestream.Write(target^,rawinfo.raw_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;
+    rawlist:TRawList;
+  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
+        rawlist:=GetRawList(fileid);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR i:=0 TO High(rawlist) DO BEGIN
+            ExportRawFile(fileid,rawlist[i].src_offset,path+'\'+GetWinFileName(filename));
+          END;
+        END;
+      END;
+    END;
+  END;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringList;
+  VAR
+    start,len:Word;
+  BEGIN
+    SetLength(Result, 0);
+    start:=1;
+    WHILE PosEx(delimiter,_string,start)>0 DO BEGIN
+      len:=PosEx(delimiter,_string,start)-start;
+      SetLength(Result, Length(Result)+1);
+      Result[High(Result)]:=MidStr(_string,start,len);
+      start:=start+len+1;
+    END;
+    SetLength(Result, Length(Result)+1);
+    Result[High(Result)]:=MidStr(_string,start,Length(_string)-start+1);
+  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.29a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.29a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,116 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.29a';
+  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;
+    FileNameHex: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];
+    FilenumbersAsHex:Boolean;
+  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;
+
+  TRawInfo=RECORD
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+    loc_sep:Boolean;
+  END;
+  TRawList=Array OF TRawInfo;
+
+VAR
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_os_mac:Boolean=False;
+  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_pc: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_ident1_mac:Array[0..$13] OF Byte=
+      ($61,$30,$C1,$23,$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.29a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.29a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,218 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, Dialogs, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset: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, Unit9_data_structures;
+
+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;
+
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    SetLength(data, GetRawInfo(fileid, dat_offset).raw_size);
+    LoadRawFileByIDOffset(fileid,dat_offset,@data[0]);
+    IF FileExists(filename+'.raw0x'+IntToHex(dat_offset,8)) THEN BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd);
+    END ELSE BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),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,$44,rawpos,Length(data),False,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.29a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Caption = 'Preview'
+  ClientHeight = 473
+  ClientWidth = 472
+  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.29a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.29a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit5_preview.pas	(revision 8)
@@ -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(GetFilesCount)+')');
+    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:=GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    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.29a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.29a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,406 @@
+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;
+  VAR
+    img_addr:LongWord;
+  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);
+    IF NOT dat_os_mac THEN
+      LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr)
+    ELSE
+      LoadDatFilePart(fileid,$A0,SizeOf(img_addr),@img_addr);
+
+    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);
+
+    IF NOT dat_os_mac THEN
+      LoadRawFile(fileid,$9C,img_addr,Result.datasize,dat_os_mac,@Result.imgdata[0])
+    ELSE
+      LoadRawFile(fileid,$A0,img_addr,Result.datasize,dat_os_mac,@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.29a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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 = 'MIP Mapping'
+      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.29a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.29a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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:=GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+
+    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:=GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+      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(GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]));
+      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.29a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.29a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.29a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,386 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 555
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 555
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+    ExplicitHeight = 423
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 555
+    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 = 450
+      Width = 483
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitTop = 375
+    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 = []
+      OnKeyUp = hexKeyUp
+      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 value_viewer: TWrapGrid
+      Left = 0
+      Top = 218
+      Width = 483
+      Height = 232
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      PopupMenu = value_viewer_context
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+    object VST: TVirtualStringTree
+      Left = 0
+      Top = 458
+      Width = 483
+      Height = 97
+      Align = alBottom
+      AnimationDuration = 0
+      AutoExpandDelay = 300
+      BiDiMode = bdLeftToRight
+      Colors.UnfocusedSelectionColor = clGradientActiveCaption
+      Colors.UnfocusedSelectionBorderColor = clGradientActiveCaption
+      Ctl3D = True
+      DragOperations = []
+      DrawSelectionMode = smBlendedRectangle
+      EditDelay = 200
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      Header.AutoSizeIndex = 0
+      Header.Font.Charset = DEFAULT_CHARSET
+      Header.Font.Color = clWindowText
+      Header.Font.Height = -11
+      Header.Font.Name = 'Tahoma'
+      Header.Font.Style = []
+      Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoVisible]
+      Header.PopupMenu = VTHPopup
+      Header.Style = hsFlatButtons
+      HintAnimation = hatNone
+      HintMode = hmTooltip
+      Indent = 14
+      ParentBiDiMode = False
+      ParentCtl3D = False
+      ParentFont = False
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 2
+      TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning]
+      TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowRoot, toShowTreeLines, toShowVertGridLines, toUseBlendedImages]
+      TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect]
+      OnDblClick = VSTDblClick
+      OnGetText = VSTGetText
+      OnHeaderDragged = VSTHeaderDragged
+      OnNewText = VSTNewText
+      Columns = <
+        item
+          MaxWidth = 300
+          MinWidth = 100
+          Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 0
+          Spacing = 20
+          Width = 150
+          WideText = 'Name'
+          WideHint = 'Name of the item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 1
+          Spacing = 20
+          Width = 85
+          WideText = 'Offset'
+          WideHint = 'Offset of the data-item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 75
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 2
+          Width = 75
+          WideText = 'Type'
+          WideHint = 'Data type of the item.'
+        end
+        item
+          MaxWidth = 250
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 3
+          Width = 80
+          WideText = 'Value'
+          WideHint = 'Value of the item.'
+        end
+        item
+          MaxWidth = 400
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 4
+          Width = 200
+          WideText = 'Description'
+        end>
+      WideDefaultText = ''
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 555
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Bevel1: TBevel
+      Left = 0
+      Top = 491
+      Width = 150
+      Height = 6
+      Align = alBottom
+      Style = bsRaised
+      ExplicitTop = 359
+    end
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 388
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 388
+      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 = 497
+      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
+  object VTHPopup: TVTHeaderPopupMenu
+    OnColumnChange = VTHPopupColumnChange
+    Left = 200
+    Top = 496
+  end
+end
Index: /oup/releases/0.29a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.29a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,962 @@
+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, Math,
+  VirtualTrees, VTHeaderPopup;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    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;
+    VST: TVirtualStringTree;
+    VTHPopup: TVTHeaderPopupMenu;
+    procedure VSTDblClick(Sender: TObject);
+    procedure VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex; NewText: WideString);
+    procedure VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+      const Column: TColumnIndex; Visible: Boolean);
+    procedure VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+      OldPosition: Integer);
+    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE LoadDat(_fileid:LongWord);
+    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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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, Unit13_rawedit;
+VAR
+  fileid:LongWord;
+
+TYPE
+  PNodeData = ^TNodeData;
+  TNodeData = record
+    Caption:String;
+    Offset:LongInt;
+    DataType:Word;
+    Value:String;
+    Description:String;
+  end;
+
+
+function AddVSTEntry(AVST:TCustomVirtualStringTree; ANode:PVirtualNode; ARecord:TNodeData):PVirtualNode;
+  var
+    data:PNodeData;
+  begin
+    Result:=AVST.AddChild(ANode);
+    data:=AVST.GetNodeData(Result);
+    AVST.ValidateNode(Result,False);
+    data^:=ARecord;
+  end;
+
+
+
+PROCEDURE TForm8.LoadDat(_fileid:LongWord);
+  VAR
+    i:LongWord;
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF GetFileIDByName(list.Items.Strings[i])=fileid THEN BEGIN
+            list.ItemIndex:=i;
+            Exit;
+          END;
+        END;
+      END;
+    END;
+    fileid:=_fileid;
+    FOR i:=0 TO list.Count-1 DO
+      IF GetFileIDByName(list.Items.Strings[i])=fileid THEN
+        list.ItemIndex:=i;
+    Self.ClearStructViewer;
+    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));
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(GetFilesCount)+')');
+    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
+    LoadDat(GetFileIDByName(list.Items.Strings[list.ItemIndex]));
+{    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF GetFileIDByName(list.Items.Strings[list.ItemIndex])=fileid THEN BEGIN
+            list.ItemIndex:=i;
+            Exit;
+          END;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    fileid:=GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    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));
+    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]);
+      11: Result:='0x'+IntToHex(GetRawInfo(fileid,offset).raw_addr,8);
+      12: Result:=FormatNumber(hex.data[offset+1]+hex.data[offset+2]*256+hex.data[offset+3]*256*256,5,'0');
+      13: Result:=IntToStr(hex.data[offset]);
+      14: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256);
+      15: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256);
+      16: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256);
+      1000..9999: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-1000 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Result:=Result+'.';
+          END;
+        END;
+      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,j:LongWord;
+    pdata: PNodeData;
+    data: TNodeData;
+    node: PVirtualNode;
+    structs: TStructDef;
+  BEGIN
+    VST.BeginUpdate;
+    IF VST.RootNodeCount=0 THEN BEGIN
+      structs:=LoadStructureDefinition(fileid);
+      IF structs.data THEN BEGIN
+        IF Length(structs.Global)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Global) DO BEGIN
+            data.Caption:=structs.Global[i].name;
+            data.Offset:=structs.Global[i].offset;
+            data.DataType:=structs.Global[i].datatype;
+            data.Value:=GetValue(structs.Global[i].datatype, structs.Global[i].offset);
+            data.Description:=structs.Global[i].description;
+            AddVSTEntry(VST, nil, data);
+          END;
+        END;
+        IF Length(structs.Subs)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Subs) DO BEGIN
+            WITH structs.Subs[i] DO BEGIN
+              IF Length(Entries)>0 THEN BEGIN
+                data.Caption:=SubName;
+                data.Offset:=0;
+                data.DataType:=0;
+                data.Value:='';
+                data.Description:='';
+                node:=AddVSTEntry(VST, nil, data);
+                FOR j:=0 TO High(Entries) DO BEGIN
+                  data.Caption:=Entries[j].name;
+                  data.Offset:=Entries[j].offset;
+                  data.DataType:=Entries[j].datatype;
+                  data.Value:=GetValue(Entries[j].datatype, Entries[j].offset);
+                  data.Description:=Entries[j].description;
+                  AddVSTEntry(VST, node, data);
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+    END ELSE BEGIN
+      Node:=VST.GetFirst;
+      WHILE Assigned(Node) DO BEGIN
+        pdata:=VST.GetNodeData(Node);
+        pdata.Value:=GetValue(pdata.Datatype, pdata.Offset);
+        Node:=VST.GetNext(Node);
+      END;
+    END;
+    VST.EndUpdate;
+
+{    VST.BeginUpdate;
+    IF VST.RootNodeCount=0 THEN BEGIN
+      IF structinfoid>=0 THEN BEGIN
+        WITH structure_infos[structinfoid] DO BEGIN
+          FOR i:=1 TO Length(entries) DO BEGIN
+            data.Caption:=entries[i-1].name;
+            data.Offset:=entries[i-1].offset;
+            data.DataType:=entries[i-1].datatype;
+            data.Value:=GetValue(entries[i-1].datatype, entries[i-1].offset);
+            data.Description:=entries[i-1].description;
+            AddVSTEntry(VST, nil, data);
+          END;
+        END;
+      END;
+    END ELSE BEGIN
+      IF structinfoid>=0 THEN BEGIN
+        WITH structure_infos[structinfoid] DO BEGIN
+          FOR i:=1 TO Length(entries) DO BEGIN
+            Node:=VST.GetFirst;
+            WHILE Assigned(Node) DO BEGIN
+              pdata:=VST.GetNodeData(Node);
+              pdata.Value:=GetValue(pdata.Datatype, pdata.Offset);
+              Node:=VST.GetNext(Node);
+            END;
+          END;
+        END;
+      END;
+    END;
+    VST.EndUpdate;
+}  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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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;
+    VST.NodeDataSize:=SizeOf(TNodeData);
+    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;
+    i:LongWord;
+  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);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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;
+  BEGIN
+    VST.Clear;
+  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.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    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.VSTDblClick(Sender: TObject);
+  var
+    node:PVirtualNode;
+    nodedata:PNodeData;
+  begin
+    if VST.FocusedColumn=3 then begin
+      node:=VST.FocusedNode;
+      nodedata:=VST.GetNodeData(node);
+
+      IF NOT (nodedata.datatype IN [11,12]) THEN BEGIN
+        Form12.MakeVarInput(nodedata.Caption,nodedata.offset,nodedata.datatype,nodedata.value,Self);
+      END ELSE BEGIN
+        IF nodedata.DataType=11 THEN BEGIN
+          IF GetRawInfo(fileid,nodedata.offset).raw_size>0 THEN BEGIN
+            IF Form1.open_child('rawedit') THEN BEGIN
+              TForm13(Form1.ActiveMDIChild).LoadRaw(GetRawInfo(fileid,nodedata.offset));
+            END;
+          END;
+        END;
+        IF nodedata.DataType=12 THEN BEGIN
+          IF (StrToInt(nodedata.Value)<GetFilesCount) AND
+              (StrToInt(nodedata.Value)>0) AND
+              (StrToInt(nodedata.Value)<>fileid) THEN BEGIN
+            IF GetFileInfo(StrToInt(nodedata.Value)).Size>0 THEN BEGIN
+              IF Form1.open_child('binedit') THEN BEGIN
+                TForm8(Form1.ActiveMDIChild).LoadDat(StrToInt(nodedata.Value));
+              END;
+            END ELSE BEGIN
+              ShowMessage('Linked filed is a zero-byte-file');
+            END;
+          END;
+        END;
+      END;
+
+    end;
+  end;
+
+procedure TForm8.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+  var
+    data:PNodeData;
+  begin
+    data := Sender.GetNodeData(Node);
+    CellText := '';
+    if TextType = ttNormal then begin
+      case Column of
+        0: CellText := data.Caption;
+        1:
+          if data.DataType>0 then
+            CellText := '0x'+IntToHex(data.Offset,8);
+        2:
+          if data.DataType>0 then
+            CellText := GetDataType(data.DataType);
+        3:
+          CellText := GetValue(data.DataType, data.Offset);
+        4:
+          CellText := data.Description;
+      end;
+    end;
+  end;
+
+procedure TForm8.VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+  OldPosition: Integer);
+  begin
+    if Sender.Columns.Items[column].Position<1 then
+      Sender.Columns.Items[column].Position:=OldPosition;
+  end;
+
+procedure TForm8.VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex; NewText: WideString);
+  var
+    Data: PNodeData;
+  begin
+    data:=Sender.GetNodeData(Node);
+{    case column of
+      3: data.Value:=Text;
+    end;
+}  end;
+
+procedure TForm8.VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+  const Column: TColumnIndex; Visible: Boolean);
+  begin
+    if column=0 then
+      TVirtualStringTree(Sender).Header.Columns.Items[column].Options:=TVirtualStringTree(Sender).Header.Columns.Items[column].Options+[coVisible];
+  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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        IF GetRawInfo(fileid,offset).raw_size>0 THEN BEGIN
+        //edit_filtername.Text:=IntToStr(GetRawInfo(fileid,offset).raw_size);
+          IF Form1.open_child('rawedit') THEN BEGIN
+            TForm13(Form1.ActiveMDIChild).LoadRaw(GetRawInfo(fileid,offset));
+          END;
+        END;
+        {LOAD RAW-EDITOR}
+      END;
+    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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+
+END.
Index: /oup/releases/0.29a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.29a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.29a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,606 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, ABSMain, DB, ABSDecUtil, Classes, Unit3_data, Dialogs, StrUtils;
+
+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
+                      // 11    : raw-addr
+                      // 12    : dat-file-ID
+                      // 13..16: Signed Integer[1..4]
+                      // 1000..9999: Unused data[0-8999]
+                      // 10000+: string[0+]
+      description:String;
+    END;
+  TStructDefSub=RECORD
+      SubName:String;
+      Entries:Array OF TStructure_entry;
+    END;
+  TStructDef=RECORD
+      Data:Boolean;
+      Global:Array OF TStructure_entry;
+      Subs:Array OF TStructDefSub;
+    END;
+  Tstructure_info=RECORD
+      extension:String;
+      typedesc:String;
+      entries:Array OF Tstructure_entry;
+    END;
+  Tstructures=Array OF Tstructure_info;
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+
+VAR
+  structure_infos:Tstructures;
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetStructureInfoId(ext:String):Integer;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+
+PROCEDURE LoadStructureDefinitions(defdir:String);
+
+
+IMPLEMENTATION
+USES Unit2_functions, Forms;
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      12: Result:=4;
+      13..16: Result:=datatype-12;
+      1000..9999: Result:=datatype-1000;
+      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';
+      11: Result:='Raw-Address';
+      12: Result:='.dat-file-ID';
+      13..16: Result:='SignedInt'+IntToStr((typeid-12)*8);
+      1000..9999: Result:='Unused('+IntToStr(typeid-1000)+')';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  VAR
+    i:LongWord;
+    raw_list:TRawList;
+  BEGIN
+    raw_list:=GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    FOR i:=0 TO High(raw_list) DO BEGIN
+      IF raw_list[i].src_offset=dat_offset THEN BEGIN
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Result.loc_sep:=raw_list[i].loc_sep;
+        Break;
+      END;
+    END;
+  END;
+
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+  VAR
+    i:LongWord;
+    Query:TABSQuery;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=0 TO High(RawListHandlers) DO
+        IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN
+          IF RawListHandlers[i].needed THEN BEGIN
+            Result:=RawListHandlers[i].Handler(fileid);
+            Break;
+          END ELSE
+            Break;
+    END ELSE BEGIN
+      SetLength(Result,0);
+      Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i].src_id:=fileid;
+          Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger;
+          Result[i].raw_addr:=0;
+          Result[i].raw_size:=Query.FieldByName('size').AsInteger;
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*4;
+        LoadDatFilePart(fileid,$20+i*4,4,@link);
+        Result[i].raw_addr:=link;
+        Result[i].raw_size:=0{????????????????????????????????};
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION AKVA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*$74+$24;
+        LoadDatFilePart(fileid,$20+i*$74+$24,4,@link);
+        Result[i].raw_addr:=link;
+        LoadDatFilePart(fileid,$20+i*$74+$28,4,@link);
+        Result[i].raw_size:=link;
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$0C,4,@link);
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$40,4,@datasize);
+      LoadDatFilePart(fileid,$44,4,@link);
+      Result[0].src_offset:=$44;
+    END ELSE BEGIN
+      LoadDatFilePart(fileid,$10,4,@datasize);
+      LoadDatFilePart(fileid,$14,4,@link);
+      Result[0].src_offset:=$14;
+    END;
+    SetLength(Result,1);
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=False;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,link:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    LoadDatFilePart(fileid,$18,4,@baselink);
+    LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      LoadDatFilePart(fileid,$20+(links-1)*4,4,@link);
+      SetLength(data,link+1024);
+      LoadRawFile(fileid,$1C,baselink,link+1024,False,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[link+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=link+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    LoadDatFilePart(fileid,$182,1,@tempb);
+    LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    LoadDatFilePart(fileid,$183,1,@tempb);
+    LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    LoadDatFilePart(fileid,$184,1,@tempb);
+    LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    LoadDatFilePart(fileid,$185,1,@tempb);
+    LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    LoadDatFilePart(fileid,$186,1,@tempb);
+    LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    LoadDatFilePart(fileid,$187,1,@tempb);
+    LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    LoadDatFilePart(fileid,$154,2,@tempw);
+    LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    LoadDatFilePart(fileid,$138,4,@templ);
+    LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link_pc:LongWord;
+    link_mac:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    LoadDatFilePart(fileid,$9C,4,@link_pc);
+    LoadDatFilePart(fileid,$A0,4,@link_mac);
+    CASE storetype OF
+      0,1,2: datasize:=x*y*2;
+      8: datasize:=x*y*4;
+      9: datasize:=x*y DIV 2;
+    END;
+    SetLength(Result,1);
+    IF NOT dat_os_mac THEN BEGIN
+      Result[0].src_offset:=$9C;
+      Result[0].raw_addr:=link_pc
+    END ELSE BEGIN
+      Result[0].src_offset:=$A0;
+      Result[0].raw_addr:=link_mac;
+    END;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  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;
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+  VAR
+    i:LongWord;
+    current_type:Byte; //0: Global, 1: Undynamic, 2: Dynamic
+    current_base,current_package,current_package_size:LongWord;
+    packages:LongWord;
+    deffile:Text;
+    structentry:TStructure_Entry;
+    fields:TStringList;
+    filename:String;
+    ext:String[4];
+    temps:String;
+    data:TData;
+  BEGIN
+    SetLength(Result.Global,0);
+    SetLength(Result.Subs,0);
+    Result.Data:=False;
+    ext:=GetFileInfo(fileid).Extension;
+    filename:=ExtractFilePath(Application.ExeName)+'\StructDefs\'+ext+'.txt';
+    IF FileExists(filename) THEN BEGIN
+      data:=LoadDatFile(fileid);
+      AssignFile(deffile,filename);
+      Reset(deffile);
+      current_type:=0;
+      Result.Data:=True;
+      IF NOT EoF(deffile) THEN BEGIN
+        ReadLn(deffile,temps);
+        WHILE NOT EoF(deffile) DO BEGIN
+          ReadLn(deffile,temps);
+          IF Length(temps)>0 THEN BEGIN
+            IF temps[1]='*' THEN BEGIN
+              fields:=Explode(temps,'#');
+              CASE Length(fields) OF
+                1: BEGIN
+                     current_type:=1;
+                     current_base:=0;
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],1,Length(fields[0])-1);
+                   END;
+                2: BEGIN
+                     current_type:=1;
+                     current_base:=HexToLong(fields[1]);
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],1,Length(fields[0])-1);
+                   END;
+                5: BEGIN
+                     current_type:=2;
+                     current_base:=HexToLong(fields[1]);
+                     current_package:=0;
+                     current_package_size:=StrToInt(fields[4]);
+                     CASE StrToInt(fields[3]) OF
+                       1: packages:=data[HexToLong(fields[2])];
+                       2: packages:=data[HexToLong(fields[2])]+data[HexToLong(fields[2])+1]*256;
+                       4: packages:=data[HexToLong(fields[2])]+data[HexToLong(fields[2])+1]*256+data[HexToLong(fields[2])+2]*256*256+data[HexToLong(fields[2])+3]*256*256*256;
+                     END;
+                     SetLength(Result.Subs, Length(Result.Subs)+packages);
+                     FOR current_package:=0 TO packages-1 DO BEGIN
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubName:=MidStr(fields[0],1,Length(fields[0])-1)+'['+IntToStr(current_package)+']';
+                     END;
+                   END;
+              END;
+            END ELSE BEGIN
+              fields:=Explode(temps,#9);
+              IF (Length(fields)=3) OR (Length(fields)=4) THEN BEGIN
+                structentry.name:=fields[0];
+                structentry.datatype:=StrToInt(fields[2]);
+                IF Length(fields)=4 THEN
+                  structentry.description:=fields[3]
+                ELSE
+                  structentry.description:='';
+                IF current_type IN [0,1] THEN BEGIN
+                  structentry.offset:=HexToLong(fields[1])+current_base;
+                  IF Length(Result.Subs)=0 THEN BEGIN
+                    SetLength(Result.Global,Length(Result.Global)+1);
+                    Result.Global[High(Result.Global)]:=structentry;
+                  END ELSE BEGIN
+                    SetLength(Result.Subs[High(Result.Subs)].Entries,Length(Result.Subs[High(Result.Subs)].Entries)+1);
+                    Result.Subs[High(Result.Subs)].Entries[High(Result.Subs[High(Result.Subs)].Entries)]:=structentry;
+                  END;
+                END ELSE BEGIN
+                  FOR current_package:=0 TO packages-1 DO BEGIN
+                    structentry.offset:=current_base+current_package*current_package_size+HexToLong(fields[1]);
+                    WITH Result.Subs[High(Result.Subs)-packages+current_package+1] DO BEGIN
+                      SetLength(Entries,Length(Entries)+1);
+                      Entries[High(Entries)]:=structentry;
+                    END;
+                  END;
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      CloseFile(deffile);
+    END;
+  END;
+
+
+  
+PROCEDURE LoadStructureDefinitionFile(filename:String);
+  VAR
+    temps:String;
+    deffile:Text;
+    ext:String;
+    fields:TStringList;
+    fieldname:String;
+    fieldoffset:LongWord;
+    fieldtype:Word;
+    fielddesc:String;
+  BEGIN
+    ext:=MidStr(ExtractFileName(filename),1,4);
+    AssignFile(deffile,filename);
+    Reset(deffile);
+    IF NOT EoF(deffile) THEN BEGIN
+      ReadLn(deffile,temps);
+      AddExtension(ext,temps);
+      WHILE NOT EoF(deffile) DO BEGIN
+        ReadLn(deffile,temps);
+        fields:=Explode(temps,#9);
+        IF (Length(fields)=3) OR (Length(fields)=4) THEN BEGIN
+          fieldname:=fields[0];
+          fieldoffset:=HexToLong(fields[1]);
+          fieldtype:=StrToInt(fields[2]);
+          IF Length(fields)=4 THEN
+            fielddesc:=fields[3]
+          ELSE
+            fielddesc:='';
+//          ShowMessage(fieldname+' - '+IntToHex(fieldoffset,4)+' - '+IntToStr(fieldtype)+' - '+fielddesc);
+          AddEntry(ext,fieldname,fieldoffset,fieldtype,fielddesc);
+        END;
+      END;
+    END;
+    CloseFile(deffile);
+  END;
+
+PROCEDURE LoadStructureDefinitions(defdir:String);
+  VAR
+    SR:TSearchRec;
+  BEGIN
+    IF DirectoryExists(defdir) THEN BEGIN
+      IF FindFirst(defdir+'\*.txt', faAnyFile, SR)=0 THEN BEGIN
+        REPEAT
+          IF (SR.Attr AND faDirectory) <> faDirectory THEN BEGIN
+            LoadStructureDefinitionFile(defdir+'\'+SR.Name);
+          END;
+        UNTIL FindNext(SR)<>0;
+      END;
+      FindClose(SR);
+    END;
+  END;
+
+BEGIN
+//  InsertRawListHandler('AGDB',True,AGDB);
+  InsertRawListHandler('AKVA',True,AKVA);
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.29a/todo.txt
===================================================================
--- /oup/releases/0.29a/todo.txt	(revision 8)
+++ /oup/releases/0.29a/todo.txt	(revision 8)
@@ -0,0 +1,158 @@
+Unit10 unabhängig, funktionsweise wiederherstellen
+Schreibt auch die dat_files[] etc
+Benutzt die *globalen* dat_stream/raw_stream und keine MemCopy
+
+-Neu laden der StructDefs per Hand
+
+-Datei von einem Tool in andrem Tool öffnen
+
+-TXMPReplace: Zugriff über Unit2
+
+
+-SELECT [src_id],MIN(datfiles.[name]),SUM(rawmap.[size]) FROM rawmap INNER  JOIN datfiles ON datfiles.[id]=[src_id] GROUP BY [src_id] ORDER BY [src_id] ASC
+
+-Extrahier-Ordner-Option (mit Platzhalter für .dat-Name)
+
+-HELP.hlp
+-About
+
+-BinEdit: Zusatzfunktionen wie: Suche, 
+-BinEdit: Bild/Menu/Button irgendwas zum speichern
+
+-Extractor: Wohin?
+
+-FileCompare: Ergebnis=Tabelle, jede Zeile eine differenz-addresse, spalten = werte an addr. für compared files
+
+-TXMP-Replace: MultiReplace
+
+-Move-Freischalter (Mindestlvl eingabe)
+
+-Löschen einer Datei auf die gelinkt wird: Liste der Links und sicherheitsfrage
+
+-Filebox-Context: Extract etc
+
+-DAT geladen -> Meldung oder sogar "what to do next?"
+-SSG: Levels extrahieren?
+-Pierre: Wie Char-Anims, Char-Models, Levels extrahieren?
+-Language-Files?
+-STRG+C auf Dateilisten etc für kopieren des Namens
+
+-REPACKING: testen lvl0: 690-collisions.txmp einbauen, script: collisions-zeug
+
+#################################################################
+##########                 File-Types                  ##########
+#################################################################
+(3CLA)
+ABNA
+AGDB
+AGQC
+AGQG
+(AGQM)
+AGQR
+AISA
+AITR
+(AIWA)
+AKAA
+AKBA
+AKBP
+AKDA
+AKEV
+AKOT
+AKVA
+BINA
+CBPI
+CBPM
+CONS
+CRSA
+DOOR
+DPge
+(EDIA)
+ENVP
+FILM
+(FXLR)
+(GMAN)
+HPge
+IDXA
+IGHH
+IGPA
+IGPG
+IGSA
+IGSt
+Impt
+IPge
+KeyI
+M3GA
+M3GM
+(M3TA)
+Mtrl
+(NMSA)
+OBAN
+OBDC
+(OBLS)
+OBOA
+OFGA
+ONCC
+ONCP
+ONCV
+ONFA
+ONGS
+ONIA
+ONLD
+ONLV
+ONMA
+ONOA
+ONSA
+ONSK
+ONTA
+ONVL
+ONWC
+OPge
+OSBD
+OTIT
+OTLF
+PLEA
+PNTA
+PSpc
+PSpL
+PSUI
+QTNA
+(QUDA)
+SNDD
+StNA
+SUBT
+(TMFA)
+(TMRA)
+TRAC
+TRAM
+TRAS
+TRBS
+TRCM
+(TRFT)
+TRGA
+TRGE
+TRIA
+TRIG
+TRMA
+TRSC
+TRTA
+TSFF
+TSFL
+TSFT
+TSGA
+TStr
+TURR
+TXAN
+TXCA
+TXMA
+TXMB
+TXMP
+(TXPC)
+TxtC
+(UUEA)
+(UVDL)
+VCRA
+WMCL
+WMDD
+WMM_
+WMMB
+WPge
Index: /oup/releases/0.29a2/StructDefs/AISA.txt
===================================================================
--- /oup/releases/0.29a2/StructDefs/AISA.txt	(revision 8)
+++ /oup/releases/0.29a2/StructDefs/AISA.txt	(revision 8)
@@ -0,0 +1,8 @@
+AI Character Setup Array
+
+File ID	$00	12
+Level ID	$04	4
+Unused	$08	1022
+Packages	$1E	2
+*AIs#$20#$1E#2#352
+Intro func	$50	10032
Index: /oup/releases/0.29a2/StructDefs/ONCC.txt
===================================================================
--- /oup/releases/0.29a2/StructDefs/ONCC.txt	(revision 8)
+++ /oup/releases/0.29a2/StructDefs/ONCC.txt	(revision 8)
@@ -0,0 +1,58 @@
+Oni character class
+TXMP link	$28	12	Shadow texture
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use an hypo
+Hurt light sound	$98	10032	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	10032	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	10032	Reference to an OSBD file of level 0
+Death sound	$F8	10032	Reference to an OSBD file of level 0
+Taunt sound query	$2B0	10	00 = not used; 64 = used
+"Whos there?" sound query	$2B1	10	00 = not used; 64 = used
+"I see you" sound query	$2B2	10	00 = not used; 64 = used
+"You lose" sound query	$2B3	10	00 = not used; 64 = used
+"Where are you?" sound query	$2B4	10	00 = not used; 64 = used
+"Why is this happenung?" sound query	$2B5	10	00 = not used; 64 = used
+Superpunch sound query	$2B6	10	00 = not used; 64 = used
+Superkick sound query	$2B7	10	00 = not used; 64 = used
+Super3 sound query	$2B8	10	00 = not used; 64 = used
+Super4 sound query	$2B9	10	00 = not used; 64 = used
+Taunt sound	$2BC	10032	Reference to a SNDD file of level 0
+"Whos there?" sound	$2DC	10032	Reference to a SNDD file of level 0
+"I see you" sound	$2FC	10032	Reference to a SNDD file of level 0
+"You lose" sound	$31C	10032	Reference to a SNDD file of level 0
+"Where are you?" sound	$33C	10032	Reference to a SNDD file of level 0
+"Why is this happenung?" sound	$35C	10032	Reference to a SNDD file of level 0
+Superpunch sound	$37C	10032	Reference to a SNDD file of level 0
+Superkick sound	$39C	10032	Reference to a SNDD file of level 0
+Super3 sound	$3BC	10032	Reference to a SNDD file of level 0
+Super4 sound	$3DC	10032	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV link	$434	12	Character varient link
+ONCP link	$438	12	Character particle array link; useless?
+ONIA link	$43C	12	Character impact array link; useless?
+Unknown	$444	10016	Maybe the weight of the character?
+Footstep walk impact	$454	10128	Reference to the a Impt file of level 0
+Footstep run impact	$4D6	10128	Reference to the a Impt file of level 0
+Footstep crouch impact	$558	10128	Reference to the a Impt file of level 0
+Fall slide impact	$5DA	10128	Reference to the a Impt file of level 0
+Fall land impact	$65C	10128	Reference to the a Impt file of level 0
+Fall land hard impact	$6DE	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$760	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$7E2	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$864	10128	Reference to the a Impt file of level 0
+Footstep turn impact	$8E6	10128	Reference to the a Impt file of level 0
+Footstep run start impact	$968	10128	Reference to the a Impt file of level 0
+Footstep single step impact	$9EA	10128	Reference to the a Impt file of level 0
+Footstep run stop impact	$A6C	10128	Reference to the a Impt file of level 0
+Footstep walk stop impact	$AEE	10128	Reference to the a Impt file of level 0
+Footstep run sprint impact	$B70	10128	Reference to the a Impt file of level 0
+Unknown	$BF4	10064	special death particles; only the mad bomber use it
+TRBS link	$C3C	8	Body set link
+TRMA link	$C40	8	Texture map array link
+CBPM link	$C44	8	Body part material link
+CBPI link	$C48	8	Body part impact link
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC link	$C88	8	Animation collection link
+TRSC link	$C8C	8	Screen (aiming) collection link
Index: /oup/releases/0.29a2/StructDefs/SUBT.txt
===================================================================
--- /oup/releases/0.29a2/StructDefs/SUBT.txt	(revision 8)
+++ /oup/releases/0.29a2/StructDefs/SUBT.txt	(revision 8)
@@ -0,0 +1,5 @@
+Subtitles
+ID	$00	4	ID of this file
+LevelID	$04	8	ID of the level this file is in
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Subtitle count	$1C	4	Number of subtitles in this file
Index: /oup/releases/0.29a2/StructDefs/TRAM.txt
===================================================================
--- /oup/releases/0.29a2/StructDefs/TRAM.txt	(revision 8)
+++ /oup/releases/0.29a2/StructDefs/TRAM.txt	(revision 8)
@@ -0,0 +1,49 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	8	Flags; It seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	8	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	8	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	2	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	10016	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	6	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
Index: /oup/releases/0.29a2/StructDefs/TXAN.txt
===================================================================
--- /oup/releases/0.29a2/StructDefs/TXAN.txt	(revision 8)
+++ /oup/releases/0.29a2/StructDefs/TXAN.txt	(revision 8)
@@ -0,0 +1,14 @@
+Texture Animation
+
+File ID	$00	12	File ID of this file
+Level Number	$04	4
+Unused	$08	1012
+
+Loop speed	$14	2
+Unknown	$16	2
+Unknown	$18	2
+Unused	$1A	1002
+Number of images	$1C	4
+
+*Packages#$20#$1C#4#4
+Image	$0	12
Index: /oup/releases/0.29a2/StructDefs/TXMP.txt
===================================================================
--- /oup/releases/0.29a2/StructDefs/TXMP.txt	(revision 8)
+++ /oup/releases/0.29a2/StructDefs/TXMP.txt	(revision 8)
@@ -0,0 +1,13 @@
+Texture
+ID	$00	12	ID of this file
+LevelID	$04	8	ID of the level this file is in
+FileName	$08	10128	
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	12	Link to the TXAN-file (if this TXMP is the first image of an animation)
+TXMP-Link	$98	12	Link to another TXMP-file
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
Index: /oup/releases/0.29a2/blubb.txt
===================================================================
--- /oup/releases/0.29a2/blubb.txt	(revision 8)
+++ /oup/releases/0.29a2/blubb.txt	(revision 8)
@@ -0,0 +1,6 @@
+___FILEINDEX___.txt
+
+
+TXMP:
+MipMapping: Bit0=an/aus
+ColorDepth: Bit0=??AnimationPic??, Bit1=shade vertex, Bit2=transparency, Bit4=16bit, Bit5=32bit
Index: /oup/releases/0.29a2/changelog.txt
===================================================================
--- /oup/releases/0.29a2/changelog.txt	(revision 8)
+++ /oup/releases/0.29a2/changelog.txt	(revision 8)
@@ -0,0 +1,90 @@
+OniUnPacker v0.29a
+------------------
++New StructureViewer
++New StructureTypes: 12=.dat-file-ID, 13..16=SignedInteger, 1000..9999=Unused data
++Dynamic Structures (look at TXAN-files or AISA-files for examples)
++File-type associations (.dat, .oldb, .opf) with OUP possible
++File IDs as Hex
+
+OniUnPacker v0.28a
+------------------
++StructureDefinitions as separate txt-files
++Minor bugfixes
++Ctrl+C for Hex-fields
+
+OniUnPacker v0.27a
+------------------
++Added MAC-file support
++Added StructureDefs for ONCCs / TRAMs (thanks to SSG)
+
+OniUnPacker v0.26a
+------------------
++Fixed some bugs again ;)
+
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.29a2/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.29a2/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.29a2/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,184 @@
+﻿<?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 Name="UnitInitSeq">True</Compiler>
+			<Compiler Name="LocalPInvoke">True</Compiler>
+			<Compiler Name="CodePage"></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 Name="GenerateHpps">False</Linker>
+		</Linker>
+		<Directories>
+			<Directories Name="OutputDir">exe</Directories>
+			<Directories Name="UnitOutputDir">dcu</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 Name="Debug Symbols Search Path"></Parameters>
+			<Parameters Name="LoadAllSymbols">True</Parameters>
+			<Parameters Name="LoadUnspecifiedSymbols">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>
+		<Language>
+			<Language Name="ActiveLang"></Language>
+			<Language Name="ProjectLang">$00000000</Language>
+			<Language Name="RootDir"></Language>
+		</Language>  
+    <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.29a2/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.29a2/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.29a2/src/OniUnPacker.cfg	(revision 8)
@@ -0,0 +1,40 @@
+-$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
+-E"exe"
+-N0"dcu"
+-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.29a2/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.29a2/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.29a2/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,31 @@
+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},
+  Unit13_rawedit in 'Unit13_rawedit.pas' {Form13},
+  Unit14_settings in 'Unit14_settings.pas' {Form14},
+  ftypesAPI in 'TFileTypeRegistration\ftypesAPI.pas';
+
+{$R *.res}
+{$R icon2.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.CreateForm(TForm12, Form12);
+  Application.CreateForm(TForm14, Form14);
+  Application.Run;
+END.
Index: /oup/releases/0.29a2/src/TFileTypeRegistration/IsAdmin.inc
===================================================================
--- /oup/releases/0.29a2/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
+++ /oup/releases/0.29a2/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
@@ -0,0 +1,90 @@
+function GetAdminSid: PSID;
+const
+  // bekannte SIDs ... (WinNT.h)
+  SECURITYNTAUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
+  // bekannte RIDs ... (WinNT.h)
+  SECURITYBUILTINDOMAINRID: DWORD = $00000020;
+  DOMAINALIASRIDADMINS: DWORD = $00000220;
+begin
+  Result := nil;
+  AllocateAndInitializeSid(SECURITYNTAUTHORITY,
+    2,
+    SECURITYBUILTINDOMAINRID,
+    DOMAINALIASRIDADMINS,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    Result);
+end;
+
+function IsAdmin: LongBool;
+var
+  TokenHandle      : THandle;
+  ReturnLength     : DWORD;
+  TokenInformation : PTokenGroups;
+  AdminSid         : PSID;
+  Loop             : Integer;
+  wv               : TOSVersionInfo;
+begin
+  wv.dwOSVersionInfoSize := sizeof(TOSversionInfo);
+  GetVersionEx(wv);
+
+  Result := (wv.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS);
+
+  if(wv.dwPlatformId = VER_PLATFORM_WIN32_NT) then
+    begin
+      TokenHandle := 0;
+      if OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, TokenHandle) then
+        try
+          ReturnLength := 0;
+          GetTokenInformation(TokenHandle, TokenGroups, nil, 0, ReturnLength);
+          TokenInformation := GetMemory(ReturnLength);
+          if Assigned(TokenInformation) then
+            try
+              if GetTokenInformation(TokenHandle, TokenGroups,
+                TokenInformation, ReturnLength, ReturnLength) then
+              begin
+                AdminSid := GetAdminSid;
+                for Loop := 0 to TokenInformation^.GroupCount - 1 do
+                  begin
+                    if EqualSid(TokenInformation^.Groups[Loop].Sid, AdminSid) then
+                      begin
+                        Result := True; break;
+                      end;
+                  end;
+                FreeSid(AdminSid);
+              end;
+            finally
+              FreeMemory(TokenInformation);
+            end;
+        finally
+          CloseHandle(TokenHandle);
+        end;
+    end;
+end;
+
+function WVersion: string; 
+var 
+  OSInfo: TOSVersionInfo; 
+begin 
+  Result := '3X'; 
+  OSInfo.dwOSVersionInfoSize := sizeof(TOSVERSIONINFO); 
+  GetVersionEx(OSInfo); 
+  case OSInfo.dwPlatformID of 
+    VER_PLATFORM_WIN32S: begin 
+        Result := '3X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_WINDOWS: begin 
+        Result := '9X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_NT: begin 
+        Result := 'NT'; 
+        Exit; 
+      end; 
+  end; //case 
+end;
Index: /oup/releases/0.29a2/src/TFileTypeRegistration/SysUtils.inc
===================================================================
--- /oup/releases/0.29a2/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
+++ /oup/releases/0.29a2/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
@@ -0,0 +1,307 @@
+function fileexists(const szFilename: string): boolean;
+var
+  Handle   : THandle;
+  FindData : TWin32FindData;
+begin
+  Handle := FindFirstFile(pchar(szFilename),FindData);
+  Result := (Handle <> INVALID_HANDLE_VALUE);
+
+  if(Result) then Windows.FindClose(Handle);
+end;
+
+function ExtractFileDrive(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') then
+    begin
+      Result := copy(szFilename,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFilePath(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFileName);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') or
+      (szFileName[i] = '\') then
+    begin
+      Result := copy(szFileName,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFileName(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '\') then
+      break;
+
+    dec(i);
+  end;
+
+  Result := copy(szFilename,i + 1,length(szFilename));
+end;
+
+function CutFileExt(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '.') then
+      break;
+
+    dec(i);
+  end;
+
+  if(i = 0) then Result := szFilename
+    else Result := copy(szFilename,1,i-1);
+end;
+
+function ChangeFileExt(const szFileName, szNewExt: string): string;
+begin
+  Result := CutFileExt(szFileName);
+
+  if(szNewExt[1] <> '.') then Result := Result + '.' + szNewExt
+    else Result := Result + szNewExt;
+end;
+
+function FileSearch(const Name, DirList: string): string;
+var
+  I, P, L: Integer;
+begin
+  Result := Name;
+  P      := 1;
+  L      := length(DirList);
+
+  while(true) do begin
+    if(fileexists(Result)) then exit;
+
+    while(P <= L) and (DirList[P] = ';') do inc(P);
+    if(P > L) then break;
+
+    I := P;
+    while(P <= L) and (DirList[P] <> ';') do inc(P);
+
+    Result   := copy(DirList,I,P-I);
+    if not(Result[length(Result)] in[':','\']) then
+      Result := Result + '\';
+
+    Result := Result + Name;
+  end;
+
+  Result  := '';
+end;
+
+function StrToIntDef(const s: string; const i: integer): integer;
+var
+  code : integer;
+begin
+  Val(s,Result,code); if(code <> 0) then
+                        Result := i;
+end;
+
+function IntToStr(const i: integer): string;
+begin
+  Str(i,Result);
+end;
+
+// -----------------------------------------------------------------------------
+
+function Format(fmt: string; params: array of const): string;
+var
+  pdw1,
+  pdw2 : PDWORD;
+  i    : integer;
+  pc   : PCHAR;
+begin
+  pdw1 := nil;
+
+  if High(params) >= 0 then
+    GetMem(pdw1, (High(params) + 1) * sizeof(Pointer));
+
+  pdw2  := pdw1;
+  for i := 0 to High(params) do
+    begin
+      pdw2^ := PDWORD(@params[i])^;
+      inc(pdw2);
+    end;
+
+  pc := GetMemory(1024);
+  if Assigned(pc) then
+    try
+      SetString(Result, pc, wvsprintf(pc, PCHAR(fmt), PCHAR(pdw1)));
+    finally
+      if (pdw1 <> nil) then FreeMem(pdw1);
+      FreeMem(pc);
+    end
+  else
+    Result := '';
+end;
+
+
+// -----------------------------------------------------------------------------
+
+function UpperCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        Result[i] := UpCase(s[i]);
+    end;
+end;
+
+function LowerCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        case s[i] of
+          'A'..'Z','Ä','Ö','Ü':
+            Result[i] := CHR(BYTE(s[i]) + 32);
+          else
+            Result[i] := s[i];
+        end;
+    end;
+end;
+
+function LoggedUser: string;
+var
+  dwLen  : dword;
+  fTest  : boolean;
+begin
+  Result := '';
+  dwLen  := MAX_PATH; SetLength(Result,dwLen);
+
+  fTest  := GetUserName(@Result[1],dwLen);
+
+  if(not fTest) and (GetLastError = ERROR_MORE_DATA) then begin
+    SetLength(Result,dwLen);
+    fTest := GetUserName(@Result[1],dwLen);
+  end;
+
+  if(fTest) and (Result[1] <> #0) then
+    SetLength(Result,dwLen - 1);
+end;
+
+// -----------------------------------------------------------------------------
+
+//
+// delete files during next reboot (code by sakura)
+//
+function DeleteFileDuringNextSystemBoot(aFileName: string): Boolean;
+var
+  ShortName,
+  winini    : string;
+  os        : TOSVersionInfo;
+  ts        : array of string;
+  f         : TextFile;
+  i         : integer;
+begin
+  Result := False;
+
+  // get OS version
+  os.dwOSVersionInfoSize := sizeof(TOSVersionInfo);
+  GetVersionEx(os);
+
+  case os.dwPlatformId of
+    // NT systems
+    VER_PLATFORM_WIN32_NT:
+      Result := MoveFileEx(pchar(aFileName),nil,
+        MOVEFILE_REPLACE_EXISTING + MOVEFILE_DELAY_UNTIL_REBOOT);
+    // 9x systems
+    VER_PLATFORM_WIN32_WINDOWS:
+      begin
+        // get Windows folder
+        SetLength(winini,MAX_PATH+1);
+        SetLength(winini,GetWindowsDirectory(@winini[1],MAX_PATH+1));
+
+        if(winini <> '') then begin
+          if(winini[length(winini)] <> '\') then
+            winini := winini + '\';
+          winini   := winini + 'wininit.ini';
+
+          // get short name of the given file
+          SetLength(ShortName,MAX_PATH+1);
+          SetLength(ShortName,
+            GetShortPathName(@aFilename[1],@ShortName[1],MAX_PATH+1));
+
+          if(ShortName <> '') then begin
+            // add it to "wininit.ini" to delete
+            // during next reboot
+            SetLength(ts,0);
+
+            {$I-}
+            // get old file´s content
+            AssignFile(f,winini);
+            ReSet(f);
+            if(IoResult = 0) then begin
+              while(not eof(f)) do begin
+                SetLength(ts,length(ts)+1);
+                ReadLn(f,ts[length(ts)-1]);
+
+                if(lstrcmpi('[rename]',pchar(ts[length(ts)-1])) = 0) then begin
+                  SetLength(ts,length(ts)+1);
+                  ts[length(ts)-1] := 'NUL='+ShortName;
+                end;
+              end;
+              CloseFile(f);
+            end;
+
+            if(length(ts) = 0) then begin
+              SetLength(ts,2);
+              ts[0] := '[rename]';
+              ts[1] := 'NUL='+ShortName;
+            end;
+
+            // re-create
+            ReWrite(f);
+            Result := (IoResult = 0);
+            if(Result) then begin
+              for i := 0 to length(ts) - 1 do
+                WriteLn(f,ts[i]);
+
+              CloseFile(f);
+            end;
+            {$I+}
+
+            SetLength(ts,0);
+          end;
+        end;
+      end;
+    // only 9x and NT are supported
+    else
+      exit;
+  end;
+end;
Index: /oup/releases/0.29a2/src/TFileTypeRegistration/demo.txt
===================================================================
--- /oup/releases/0.29a2/src/TFileTypeRegistration/demo.txt	(revision 8)
+++ /oup/releases/0.29a2/src/TFileTypeRegistration/demo.txt	(revision 8)
@@ -0,0 +1,34 @@
+uses
+  ftypesAPI;
+
+var
+  ftr    : TFileTypeRegistration;
+  s:String;
+
+
+ftr := TFileTypeRegistration.Create;
+if(ftr <> nil) then begin
+  try
+    if(LOWORD(wp) = IDC_CREATEFOO) then begin
+      if(ftr.RegisterType('.foo','FooFile','FOO-File')) then begin
+        ftr.AddHandler('open','notepad.exe "%1"','Öffnen');
+        ftr.AddHandler('print','notepad.exe /p "%1"');
+        ftr.SetDefaultHandler;
+        ftr.AddNewFileSupport('.foo');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_DELPRINTVERB) then begin
+      if(ftr.GetInternalKey('.foo') <> '') then begin
+        ftr.DeleteHandler('print');
+        ftr.SetDefaultHandler('open');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_REMOVEFOO) then begin
+      s := ftr.GetInternalKey('.foo');
+      if(MessageBox(hwndDlg,pchar('Wollen Sie wirklich ".foo" und "' + s + '" entfernen?'), 'Frage',MB_YESNO or MB_DEFBUTTON2 or MB_ICONQUESTION) = ID_YES) then
+        ftr.UnregisterType('.foo');
+    end;
+  finally
+    ftr.Free;
+  end;
+end;
Index: /oup/releases/0.29a2/src/TFileTypeRegistration/ftypesAPI.pas
===================================================================
--- /oup/releases/0.29a2/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
+++ /oup/releases/0.29a2/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
@@ -0,0 +1,544 @@
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse (Win32-API)
+// Copyright (c) 2004 Mathias Simmack
+//
+// -----------------------------------------------------------------------------
+
+// -- Revision history ---------------------------------------------------------
+//
+//   * erste Version
+//
+// -----------------------------------------------------------------------------
+unit ftypesAPI;
+
+interface
+
+uses
+  Windows, ShlObj;
+
+type
+  TFileTypeRegistration = class
+    FRegConnector : HKEY;
+    FExtension,
+    FInternalName : string;
+    FVerb         : string;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function RegisterType(const Extension, InternalName: string;
+      Description: string = ''; IconFile: string = '';
+      IconIndex: integer = -1): boolean;
+    function UnregisterExtension(const Extension: string): boolean;
+    function UnregisterType(const Extension: string): boolean;
+    procedure UpdateShell;
+    function AddHandler(const HandlerVerb, CommandLine: string;
+      HandlerDescription: string = ''): boolean; overload;
+    function DeleteHandler(const HandlerVerb: string): boolean;
+    function SetDefaultHandler: boolean; overload;
+    function SetDefaultHandler(const HandlerVerb: string): boolean; overload;
+    function GetInternalKey(const Extension: string): string;
+    function AddNewFileSupport(const Extension: string): boolean;
+    function RemoveNewFileSupport(const Extension: string): boolean;
+
+    property Extension: string read FExtension;
+    property InternalName: string read FInternalName;
+    property CurrentVerb: string read FVerb;
+  end;
+
+
+implementation
+
+(* *****************************************************************************
+
+  Beispiel #1: Einen neuen Dateityp registrieren
+  ----------------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // die Dateiendung ".foo" registrieren, der interne Schlüssel
+    // lautet "FooFile", eine Beschreibung und eine Symboldatei
+    // sind ebenfalls angegeben
+    if(ftr.RegisterType('.foo','FooFile','FOO Description',
+      'c:\folder\icon.ico')) then
+    begin
+      // fügt den Handler "open" hinzu und verknüpft ihn mit dem
+      // Programm "foo.exe"
+      ftr.AddHandler('open','"c:\folder\foo.exe" "%1"');
+
+      // setzt den zuletzt benutzten Handler ("open" in dem Fall)
+      // als Standard
+      ftr.SetDefaultHandler;
+    end;
+
+    if(ftr.RegisterType('.foo','ThisIsNotTheFOOKey')) then
+    // Das ist kein Fehler! Obwohl hier der interne Name
+    // "ThisIsNotTheFOOKey" verwendet wird, benutzt die Funktion
+    // intern den bereits vorhandenen Schlüssel "FooFile" (s. oben).
+    begin
+      // zwei neue Handler werden registriert, ...
+      ftr.AddHandler('print','"c:\folder\foo.exe" /p "%1"');
+      ftr.AddHandler('edit','notepad.exe "%1"');
+
+      // ... & dank der überladenen Funktion "SetDefaultHandler"
+      // kann diesmal auch "print" als Standardhandler gesetzt
+      // werden
+      ftr.SetDefaultHandler('print');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #2: Einen neuen Typ mit einem vorhandenen Schlüssel
+  verknüpfen
+  ------------------------------------------------------------
+
+  Das Beispiel registriert die Endung ".foo" auf die gleiche
+  Weise wie Textdateien (.txt). Es wird einfach der interne
+  Schlüsselname ermittelt und für die Endung ".foo" gesetzt
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    strInternalTextFileKey := ftr.GetInternalKey('.txt');
+    if(strInternalTextFileKey <> '') then
+      ftr.RegisterType('.foo',strInternalTextFileKey);
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #3: Einen Handler entfernen
+  ------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // den internen Schlüsselnamen des Typs ".foo" ermitteln, ...
+    if(ftr.GetInternalKey('.foo') <> '') then
+    // ... wobei das Ergebnis in dem Fall unwichtig ist, weil
+    // intern auch die Eigenschaft "FInternalName" gesetzt
+    // wird
+    begin
+      // den "print"-Handler entfernen, ...
+      ftr.DeleteHandler('print');
+
+      // ... & den Standardhandler aktualisieren
+      ftr.SetDefaultHandler('open');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #4: Nur eine Dateiendung entfernen
+  -------------------------------------------
+
+  In diesem Fall wird lediglich die Endung ".foo" entfernt. Der
+  evtl. vorhandene interne Schlüssel bleibt bestehen. Das ist
+  für das Beispiel #2 nützlich, wenn die Endung ".foo" entfernt
+  werden soll, intern aber mit den Textdateien verlinkt ist, die
+  ja im Normalfall nicht entfernt werden dürfen/sollten.
+
+    ftr.UnregisterExtension('.foo');
+
+
+  Beispiel #5: Den kompletten Dateityp entfernen
+  ----------------------------------------------
+
+  Dieses Beispiel entfernt dagegen den kompletten Dateityp,
+  inkl. des evtl. vorhandenen internen Schlüssels (vgl. mit
+  Beispiel #4).
+
+    ftr.UnregisterType('.foo');
+
+  Bezogen auf Beispiel #2 wäre das die fatale Lösung, weil dadurch
+  zwar die Endung ".foo" deregistriert wird, gleichzeitig wird
+  aber auch der intern verwendete Schlüssel der Textdateien
+  gelöscht.
+
+  ALSO, VORSICHT!!!
+
+***************************************************************************** *)
+
+
+//
+// Admin-Rechte sind erforderlich (Funktion von NicoDE)
+//
+{$INCLUDE IsAdmin.inc}
+{$INCLUDE SysUtils.inc}
+
+
+// -----------------------------------------------------------------------------
+//
+// Registry
+//
+// -----------------------------------------------------------------------------
+
+function RegWriteSubKeyVal(const parent: HKEY; SubKeyName: string;
+  ValueName, Value: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := false;
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegCreateKeyEx(parent,pchar(SubKeyName),0,nil,0,KEY_READ or KEY_WRITE,
+    nil,tmp,nil) = ERROR_SUCCESS) then
+  try
+    Result := (RegSetValueEx(tmp,pchar(ValueName),0,REG_SZ,pchar(Value),
+      length(Value) + 1) = ERROR_SUCCESS);
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegReadSubKeyStr(const parent: HKEY; SubKeyName: string;
+  ValueName: string): string;
+var
+  tmp     : HKEY;
+  lpData,
+  dwLen   : dword;
+begin
+  Result  := '';
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegOpenKeyEx(parent,pchar(SubKeyName),0,KEY_READ,
+    tmp) = ERROR_SUCCESS) then
+  try
+    lpData := REG_NONE;
+    dwLen  := 0;
+    if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,nil,
+         @dwLen) = ERROR_SUCCESS) and
+      (lpData in[REG_SZ,REG_EXPAND_SZ]) and
+      (dwLen > 0) then
+    begin
+      SetLength(Result,dwLen);
+
+      if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,
+           @Result[1],@dwLen) = ERROR_SUCCESS) then
+        SetLength(Result,dwLen - 1)
+      else
+        Result := '';
+    end;
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegKeyExists(const parent: HKEY; KeyName: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := (RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,tmp) =
+    ERROR_SUCCESS);
+  if(Result) then RegCloseKey(tmp);
+end;
+
+function RegDeleteWholeKey(parent: HKEY; KeyName: string): boolean;
+var
+  reg       : HKEY;
+  dwSubkeys : dword;
+  dwLen     : dword;
+  i         : integer;
+  buf       : array[0..MAX_PATH]of char;
+begin
+  if(RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,reg) = ERROR_SUCCESS) then
+  try
+    if(RegQueryInfoKey(reg,nil,nil,nil,@dwSubKeys,nil,
+      nil,nil,nil,nil,nil,nil) = ERROR_SUCCESS) and
+      (dwSubKeys > 0) then
+    for i := 0 to dwSubKeys - 1 do begin
+      ZeroMemory(@buf,sizeof(buf));
+      dwLen   := MAX_PATH;
+
+      if(RegEnumKeyEx(reg,i,buf,dwLen,nil,nil,nil,nil) = ERROR_SUCCESS) and
+        (dwLen > 0) then
+      RegDeleteWholeKey(reg,buf);
+    end;
+  finally
+    RegCloseKey(reg);
+  end;
+
+  Result := (RegDeleteKey(parent,pchar(KeyName)) = ERROR_SUCCESS);
+end;
+
+
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse
+//
+// -----------------------------------------------------------------------------
+
+constructor TFileTypeRegistration.Create;
+var
+  key: HKEY;
+  sub: PChar;
+begin
+  FExtension    := '';
+  FInternalName := '';
+  FVerb         := '';
+
+  // Zugriff auf die Registry, & HKEY_CLASSES_ROOT
+  // als Root setzen
+  if(WVersion='9X') or IsAdmin then begin
+    key:=HKEY_CLASSES_ROOT;
+    sub:=nil;
+  end else begin
+    key:=HKEY_CURRENT_USER;
+    sub:=PChar('SOFTWARE\Classes');
+  end;
+
+  if RegOpenKeyEx(key,sub,0,KEY_ALL_ACCESS, FRegConnector) <> ERROR_SUCCESS then
+    FRegConnector := INVALID_HANDLE_VALUE;
+end;
+
+destructor TFileTypeRegistration.Destroy;
+begin
+  if(FRegConnector <> INVALID_HANDLE_VALUE) then
+    RegCloseKey(FRegConnector);
+end;
+
+function TFileTypeRegistration.RegisterType(const Extension,
+  InternalName: string; Description: string = ''; IconFile: string = '';
+  IconIndex: integer = -1): boolean;
+var
+  strDummy : string;
+begin
+  // Standardergebnis
+  Result         := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // ist dieser Typ evtl. schon registriert?
+  strDummy := self.GetInternalKey(Extension);
+
+  // Nein. :o)
+  if(strDummy = '') then strDummy := InternalName;
+
+  // den Schlüssel mit der Dateiendung anlegen oder aktualisieren
+  Result := RegWriteSubKeyVal(FRegConnector,Extension,'',strDummy);
+  if(not Result) then exit;
+
+  // den internen Schlüssel öffnen
+  if(Result) then
+  begin
+    // Beschreibung anlegen
+    if(Description <> '') then
+      RegWriteSubKeyVal(FRegConnector,strDummy,'',Description);
+
+    // Symbol zuweisen (Datei muss existieren!)
+    if(IconFile <> '') and
+      (fileexists(IconFile)) then
+    begin
+      if(IconIndex <> -1) then
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',Format('%s,%d',[IconFile,IconIndex]))
+      else
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',IconFile);
+    end;
+  end;
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+
+  // Properties aktualisieren
+  if(Result) then
+  begin
+    FExtension    := Extension;
+    FInternalName := strDummy;
+  end;
+end;
+
+function TFileTypeRegistration.UnregisterExtension(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // die Endung entfernen
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegDeleteWholeKey(FRegConnector,Extension));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+function TFileTypeRegistration.UnregisterType(const Extension: string):
+  boolean;
+var
+  strDummy : string;
+begin
+  Result   := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // den internen Namen der Endung ermitteln
+  strDummy := self.GetInternalKey(Extension);
+
+  // die Endung entfernen (s. "UnregisterExtension"), ...
+  Result   := (self.UnregisterExtension(Extension)) and
+  // ... & den internen Schlüssel löschen
+    (strDummy <> '') and
+    (RegKeyExists(FRegConnector,strDummy)) and
+    (RegDeleteWholeKey(FRegConnector,strDummy));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+procedure TFileTypeRegistration.UpdateShell;
+begin
+  SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,nil,nil);
+end;
+
+
+const
+  ShellKey = '%s\shell\%s';
+
+function TFileTypeRegistration.AddHandler(const HandlerVerb,
+  CommandLine: string; HandlerDescription: string = ''): boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') or
+    (CommandLine = '') then exit;
+
+  // der interne Schlüssel muss existieren
+  if(RegKeyExists(FRegConnector,FInternalName)) then
+  begin
+    // den Handler (= Verb) erzeugen
+    Result := RegWriteSubKeyVal(FRegConnector,
+      Format(ShellKey + '\command',[FInternalName,HandlerVerb]),
+      '',
+      CommandLine);
+
+    // ggf. Beschreibung für Handler setzen
+    if(HandlerDescription <> '') then
+      RegWriteSubKeyVal(FRegConnector,
+        Format(ShellKey,[FInternalName,HandlerVerb]),
+        '',
+        HandlerDescription);
+  end;
+
+  // interne Eigenschaft anpassen (für "SetDefaultHandler")
+  if(Result) then
+    FVerb := HandlerVerb;
+end;
+
+function TFileTypeRegistration.DeleteHandler(const HandlerVerb: string):
+  boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // Handlerschlüssel entfernen (sofern vorhanden)
+  Result :=
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) and
+    (RegDeleteWholeKey(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb])));
+end;
+
+function TFileTypeRegistration.SetDefaultHandler: boolean;
+begin
+  if(FInternalName <> '') and (FVerb <> '') then
+    Result := self.SetDefaultHandler(FVerb)
+  else
+    Result := false;
+end;
+
+function TFileTypeRegistration.SetDefaultHandler(const HandlerVerb: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // interner Schlüssel muss existieren, ...
+  if(RegKeyExists(FRegConnector,FInternalName)) and
+  // ... & Handler muss existieren, ...
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) then
+  begin
+  // ... dann den Handler als Standard eintragen
+    Result := RegWriteSubKeyVal(FRegConnector,FInternalName + '\shell',
+      '',HandlerVerb);
+  end;
+end;
+
+function TFileTypeRegistration.GetInternalKey(const Extension: string): string;
+begin
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // einen evtl. eingestellten internen Namen zurücksetzen
+  FInternalName   := '';
+
+  // den Schlüssel der Dateiendung öffnen, ...
+  if(RegKeyExists(FRegConnector,Extension)) then
+    FInternalName := RegReadSubKeyStr(FRegConnector,Extension,'');
+
+  // ... als Funktionsergebnis zurückliefern
+  if(not RegKeyExists(FRegConnector,FInternalName)) then
+    FInternalName := '';
+
+  Result := FInternalName;
+end;
+
+
+function TFileTypeRegistration.AddNewFileSupport(const Extension: string):
+  boolean;
+var
+  Description : string;
+begin
+  Result      := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // interne Beschreibung des Typs ermitteln
+  if(self.GetInternalKey(Extension) <> '') then
+    Description := RegReadSubKeyStr(FRegConnector,FInternalName,'')
+  else
+    Description := '';
+
+  // die Beschreibung darf keine Leerzeichen enthalten, weil sie
+  // als Referenz für den neuen Dateinamen verwendet wird, ...
+  if(pos(#32,Description) > 0) or
+  // ... & sie darf auch nicht leer sein
+    (Description = '') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegWriteSubKeyVal(FRegConnector,Extension + '\ShellNew','NullFile',''));
+end;
+
+function TFileTypeRegistration.RemoveNewFileSupport(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension + '\ShellNew')) and
+    (RegDeleteWholeKey(FRegConnector,Extension + '\ShellNew'));
+end;
+
+end.
Index: /oup/releases/0.29a2/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.29a2/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,952 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit9_data_structures;
+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;
+  raw_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.CreateLevel(source,target:String);
+  VAR
+    i:LongWord;
+  BEGIN
+  END;
+
+PROCEDURE TForm10.CreateDatabase(source,target:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+  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:=target;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=loaded_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:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    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;
+
+        rawlist:=GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              mem:=TMemoryStream.Create;
+              filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+              filestream.Seek(rawlist[j].raw_addr,soFromBeginning);
+              mem.CopyFrom(filestream,rawlist[j].raw_size);
+              filestream.Free;
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") );';
+              Query.ExecSQL;
+              mem.Free;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        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 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 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 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 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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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',False,NIL);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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.29a2/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+object Form11: TForm11
+  Left = 0
+  Top = 0
+  Caption = 'Extractor'
+  ClientHeight = 398
+  ClientWidth = 487
+  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
+      MultiSelect = True
+      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.29a2/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit11_extractor.pas	(revision 8)
@@ -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(GetFilesCount)+')');
+    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(GetFileIDByName(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+            END ELSE BEGIN
+              ExportFile(GetFileIDByName(list.Items.Strings[list.ItemIndex]),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(GetFileIDByName(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+          END ELSE BEGIN
+            ExportFile(GetFileIDByName(list.Items.Strings[list.ItemIndex]),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.29a2/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.29a2/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,119 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      13..16: BEGIN
+              Exit;
+              edit_new.EditType:=etInteger;
+              edit_new.LimitCheck:=True;
+              edit_new.Max:=Int((Power(256,datatype-13)) / 2)-1;
+              edit_new.Min:=1-Int((Power(256,datatype-13)) / 2)-1;
+            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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.29a2/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,324 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  ClientHeight = 640
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = []
+      OnKeyUp = hexKeyUp
+      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 = 600
+      Width = 483
+      Height = 40
+      Align = alBottom
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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 = 374
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 337
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 352
+        Width = 146
+        Height = 88
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        OnResize = panel_extensionResize
+        object lbl_filter: TLabel
+          Left = 2
+          Top = 46
+          Width = 100
+          Height = 17
+          AutoSize = False
+          Caption = 'Filter by &extension:'
+          FocusControl = combo_extension
+        end
+        object combo_extension: TComboBox
+          Left = 2
+          Top = 60
+          Width = 145
+          Height = 21
+          Style = csDropDownList
+          DropDownCount = 12
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Tahoma'
+          Font.Style = []
+          ItemHeight = 0
+          ParentFont = False
+          Sorted = True
+          TabOrder = 2
+          OnClick = combo_extensionClick
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.29a2/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,809 @@
+UNIT Unit13_rawedit;
+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, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+  dat_offset:LongWord;
+  fileid_opened,dat_offset_opened:LongWord;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    IF list_offset.Count=0 THEN BEGIN
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF GetFileIDByName(list.Items.Strings[i])=raw_info.src_id THEN BEGIN
+          list.ItemIndex:=i;
+          listClick(Self);
+          Break;
+        END;
+      END;
+      FOR i:=0 TO list_offset.Count-1 DO BEGIN
+        IF MidStr(list_offset.Items.Strings[i],3,8)=IntToHex(raw_info.src_offset,8) THEN BEGIN
+          list_offset.ItemIndex:=i;
+          Break;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    LoadRawFilebyIDOffset(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+    count:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=GetExtensionsList;
+    FOR i:=0 TO High(RawListHandlers) DO BEGIN
+      count:=Length(GetFilesList(RawListHandlers[i].Ext,'',True));
+      combo_extension.Items.Add(RawListHandlers[i].ext+' ('+IntToStr(count)+')');
+    END;
+//    FOR i:=0 TO High(exts) DO
+//      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm13.LoadFileNames;
+  VAR
+    Extension:String;
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN BEGIN
+      Extension:='';
+      FOR i:=0 TO High(RawListHandlers) DO BEGIN
+        IF Length(Extension)>0 THEN Extension:=Extension+',';
+        Extension:=Extension+RawListHandlers[i].Ext;
+      END;
+    END;
+
+    files:=GetFilesList(extension,pattern,TRUE);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    list_offset.Enabled:=True;
+    IF GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,8)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,8));
+    LoadRaw(GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of 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;
+          UpdateRawFile(GetRawInfo(fileid_opened,dat_offset_opened),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+{      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+}    END;
+  END;
+
+PROCEDURE TForm13.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  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
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+*)    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.29a2/src/Unit14_settings.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit14_settings.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit14_settings.dfm	(revision 8)
@@ -0,0 +1,75 @@
+object Form14: TForm14
+  Left = 0
+  Top = 0
+  BorderStyle = bsToolWindow
+  Caption = 'Settings'
+  ClientHeight = 350
+  ClientWidth = 250
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object check_filesashex: TCheckBox
+    Left = 8
+    Top = 8
+    Width = 145
+    Height = 17
+    Caption = 'Show filenumbers as Hex'
+    TabOrder = 0
+  end
+  object btn_ok: TButton
+    Left = 8
+    Top = 319
+    Width = 57
+    Height = 23
+    Caption = 'OK'
+    Default = True
+    TabOrder = 1
+    OnClick = btn_okClick
+  end
+  object btn_cancel: TButton
+    Left = 120
+    Top = 319
+    Width = 57
+    Height = 23
+    Cancel = True
+    Caption = 'Cancel'
+    TabOrder = 2
+    OnClick = btn_cancelClick
+  end
+  object btn_register_oldb: TButton
+    Left = 8
+    Top = 128
+    Width = 169
+    Height = 25
+    Caption = 'Register .oldb files with OUP'
+    TabOrder = 3
+    OnClick = btn_register_oldbClick
+  end
+  object btn_register_opf: TButton
+    Left = 8
+    Top = 159
+    Width = 169
+    Height = 25
+    Caption = 'Register .opf files with OUP'
+    TabOrder = 4
+    OnClick = btn_register_opfClick
+  end
+  object btn_register_dat: TButton
+    Left = 8
+    Top = 97
+    Width = 169
+    Height = 25
+    Caption = 'Register .dat files with OUP'
+    TabOrder = 5
+    OnClick = btn_register_datClick
+  end
+end
Index: /oup/releases/0.29a2/src/Unit14_settings.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit14_settings.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit14_settings.pas	(revision 8)
@@ -0,0 +1,155 @@
+unit Unit14_settings;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils;
+
+type
+  TForm14 = class(TForm)
+    check_filesashex: TCheckBox;
+    btn_ok: TButton;
+    btn_cancel: TButton;
+    btn_register_oldb: TButton;
+    btn_register_opf: TButton;
+    btn_register_dat: TButton;
+    procedure btn_register_opfClick(Sender: TObject);
+    procedure btn_register_oldbClick(Sender: TObject);
+    procedure btn_register_datClick(Sender: TObject);
+    procedure btn_cancelClick(Sender: TObject);
+    procedure btn_okClick(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormShow(Sender: TObject);
+    function RegisterExtension(ext:String):Integer;
+  private
+  public
+  end;
+
+var
+  Form14: TForm14;
+
+implementation
+{$R *.dfm}
+uses
+  Unit1_main, Unit3_data, ftypesAPI;
+
+function ExtensionRegistered(ext:String; var RegisteredAs:String):Boolean;
+  var
+    ftr:TFileTypeRegistration;
+  begin
+    ftr:=TFileTypeRegistration.Create;
+    if(ftr <> nil) then begin
+      try
+        RegisteredAs:=ftr.GetInternalKey(ext);
+        if RegisteredAs<>'' then
+          Result:=True
+        else
+          Result:=False;
+      finally
+        ftr.Free;
+      end;
+    end;
+  end;
+
+function TForm14.RegisterExtension(ext:String):Integer;
+  var
+    ftr:TFileTypeRegistration;
+    temps:String;
+    warnmsg:String;
+  begin
+    Result:=-1;
+    if ExtensionRegistered(ext,temps) then begin
+      if temps<>'ONI'+ext then begin
+        warnmsg:=ext+'-files are not registered to OUP but as "'+temps+'"-files.'+#13+#10+
+                 'Do you really want to unregister'+ext+'-files?';
+        if MessageBox(Self.Handle, PChar(warnmsg),PChar('Warning'),MB_YESNO)=ID_NO then
+          Exit;
+      end;
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then
+        try
+          if not ftr.UnregisterExtension(ext) then
+            ShowMessage('Could not unregister '+ext+'-files')
+          else
+            Result:=2;
+        finally
+          ftr.Free;
+        end;
+    end else begin
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then begin
+        try
+          if ftr.RegisterType(ext,'ONI'+ext,'ONI '+ext+'-file',Application.EXEname+',1') then begin
+            ftr.AddHandler('open','"'+Application.EXEname+'" '+MidStr(ext,2,Length(ext)-1)+' "%1"');
+            ftr.SetDefaultHandler;
+            Result:=1;
+          end;
+        finally
+          ftr.Free;
+        end;
+      end;
+    end;
+  end;
+
+procedure TForm14.btn_cancelClick(Sender: TObject);
+  begin
+    Self.Close;
+  end;
+
+procedure TForm14.btn_okClick(Sender: TObject);
+  begin
+    AppSettings.FilenumbersAsHex:=check_filesashex.Checked;
+    Self.Close;
+  end;
+
+procedure TForm14.btn_register_datClick(Sender: TObject);
+  begin
+    case RegisterExtension('.dat') of
+      2: btn_register_dat.Caption:='Register .dat files with OUP';
+      1: btn_register_dat.Caption:='Unregister .dat files';
+    end;
+  end;
+
+procedure TForm14.btn_register_oldbClick(Sender: TObject);
+  begin
+    case RegisterExtension('.oldb') of
+      2: btn_register_oldb.Caption:='Register .oldb files with OUP';
+      1: btn_register_oldb.Caption:='Unregister .oldb files';
+    end;
+  end;
+
+procedure TForm14.btn_register_opfClick(Sender: TObject);
+  begin
+    case RegisterExtension('.opf') of
+      2: btn_register_opf.Caption:='Register .opf files with OUP';
+      1: btn_register_opf.Caption:='Unregister .opf files';
+    end;
+  end;
+
+procedure TForm14.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  begin
+    CanClose:=False;
+    Self.Visible:=False;
+    Form1.Enabled:=True;
+    Form1.SetFocus;
+  end;
+
+procedure TForm14.FormShow(Sender: TObject);
+  var
+    temps:String;
+  begin
+    if ExtensionRegistered('.dat',temps) then
+      btn_register_dat.Caption:='Unregister .dat files'
+    else
+      btn_register_dat.Caption:='Register .dat files with OUP';
+    if ExtensionRegistered('.oldb',temps) then
+      btn_register_oldb.Caption:='Unregister .oldb files'
+    else
+      btn_register_oldb.Caption:='Register .oldb files with OUP';
+    if ExtensionRegistered('.opf',temps) then
+      btn_register_opf.Caption:='Unregister .opf files'
+    else
+      btn_register_opf.Caption:='Register .opf files with OUP';
+    check_filesashex.Checked:=AppSettings.FilenumbersAsHex;
+  end;
+
+end.
Index: /oup/releases/0.29a2/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  Caption = 'Form1'
+  ClientHeight = 525
+  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 = 508
+    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
+    ExplicitTop = 489
+  end
+  object tabs: TTabSet
+    Left = 0
+    Top = 488
+    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
+    ExplicitTop = 469
+  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 ClosefileDB1: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = ClosefileDB1Click
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_settings: TMenuItem
+        Caption = 'Se&ttings...'
+        OnClick = menu_settingsClick
+      end
+      object menu_sep4: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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
+    object menu_About: TMenuItem
+      Caption = '&About'
+      OnClick = menu_AboutClick
+    end
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 520
+  end
+end
Index: /oup/releases/0.29a2/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,526 @@
+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, Unit9_data_structures,
+  Unit10_leveldb, Unit4_exporters, Unit14_settings,
+  Unit5_preview, Unit7_txmpreplace, Unit8_binedit, Unit11_extractor, Unit13_rawedit;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    ClosefileDB1: TMenuItem;
+    menu_sep4: TMenuItem;
+    menu_settings: TMenuItem;
+    menu_About: TMenuItem;
+    procedure menu_AboutClick(Sender: TObject);
+    PROCEDURE menu_settingsClick(Sender: TObject);
+    PROCEDURE ClosefileDB1Click(Sender: TObject);
+    PROCEDURE menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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;
+
+    IF MidStr(ParamStr(1),1,3)='opf' THEN BEGIN
+      ShowMessage('Load OPF-File: '+ParamStr(2));
+    END ELSE IF MidStr(ParamStr(1),1,4)='oldb' THEN BEGIN
+      OpenDatabase(ParamStr(2));
+      IF opened_state=opened_db THEN BEGIN
+        menu_tools.Enabled:=True;
+        menu_convert.Enabled:=False;
+        statbar.Panels.Items[0].Text:='OLDB loaded: '+ParamStr(2);
+        statbar.Panels.Items[1].Text:='Files: '+IntToStr(GetFilesCount);
+        statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(GetExtensionsList));
+      END ELSE BEGIN
+        menu_tools.Enabled:=False;
+        menu_convert.Enabled:=True;
+      END;
+    END ELSE IF MidStr(ParamStr(1),1,3)='dat' THEN BEGIN
+      IF LoadDatInfos(ParamStr(2)) THEN BEGIN
+        Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(ParamStr(2))+')';
+        statbar.Panels.Items[0].Text:='.dat loaded: '+ParamStr(2);
+        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:=False;
+      END ELSE BEGIN
+        menu_convert.Enabled:=True;
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+        END ELSE BEGIN
+          menu_convert.Enabled:=True;
+          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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+          statbar.Panels.Items[0].Text:='OLDB loaded: '+opend.FileName;
+          statbar.Panels.Items[1].Text:='Files: '+IntToStr(GetFilesCount);
+          statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(GetExtensionsList));
+        END ELSE BEGIN
+          menu_tools.Enabled:=False;
+          menu_convert.Enabled:=True;
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.ClosefileDB1Click(Sender: TObject);
+  BEGIN
+    menu_windows_closeallClick(Form1);
+    IF Length(tablist)=0 THEN BEGIN
+      IF opened_state=opened_db THEN CloseDatabase;
+      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: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+PROCEDURE TForm1.menu_settingsClick(Sender: TObject);
+  BEGIN
+    Form14.Visible:=True;
+    Self.Enabled:=False;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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.menu_AboutClick(Sender: TObject);
+  begin
+    ShowMessage('Will be implemented later ;)');
+  end;
+
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.29a2/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,683 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data, 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 GetFilesCount:LongWord;
+FUNCTION GetExtensionsList:TStringList;
+FUNCTION GetFileIDByName(name:String):LongWord;
+
+FUNCTION HexToLong(hex:String):LongWord;
+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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+FUNCTION LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; 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;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringList;
+
+
+IMPLEMENTATION
+USES Unit4_Exporters, Unit9_data_structures;
+
+VAR
+  Database:TABSDatabase;
+  Query:TABSQuery;
+
+TYPE
+  TValueSwitcher=Record
+    CASE IsFloat: Boolean OF
+      True: (ValueFloat:Single);
+      False: (ValueInt:LongWord);
+  END;
+
+FUNCTION NormalizeHexString(VAR hex:String):Boolean;
+  VAR
+    i:Byte;
+  BEGIN
+    IF hex[1]='$' THEN BEGIN
+      FOR i:=1 TO Length(hex)-1 DO BEGIN
+        hex[i]:=hex[i+1];
+      END;
+      SetLength(hex, Length(hex)-1);
+    END;
+    IF (hex[1]='0') AND (UpCase(hex[2])='X') THEN BEGIN
+      FOR i:=1 TO Length(hex)-2 DO BEGIN
+        hex[i]:=hex[i+2];
+      END;
+      SetLength(hex, Length(hex)-2);
+    END;
+    IF Length(hex)=0 THEN
+      Result:=False
+    ELSE
+      Result:=True;
+  END;
+
+FUNCTION HexToLong(hex:String):LongWord;
+  VAR
+    i:Byte;
+  BEGIN
+    IF NormalizeHexString(hex) THEN BEGIN
+      hex:=UpperCase(hex);
+      Result:=0;
+      FOR i:=1 TO Length(hex) DO BEGIN
+        Result:=Result SHL 4;
+        CASE hex[i] OF
+          '0'..'9': Result:=Result+Ord(hex[i])-48;
+          'A'..'F': Result:=Result+Ord(hex[i])-55;
+        ELSE
+          Result:=0;
+          Exit;
+        END;
+      END;
+    END ELSE BEGIN
+      Result:=0;
+    END;
+  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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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:=Query.FieldByName('size').AsInteger;
+        Result.FileType:=Query.FieldByName('contenttype').AsInteger;
+        Result.DatAddr:=0;
+        Result.opened:=False;
+      END;
+      Query.Close;
+    END;
+  END;
+
+FUNCTION GetFileIDByName(name:String):LongWord;
+  BEGIN
+    IF AppSettings.FilenumbersAsHex THEN
+      Result:=HexToLong(MidStr(name,1,4))
+    ELSE
+      Result:=StrToInt(MidStr(name,1,5));
+  END;
+
+FUNCTION GetFilesCount:LongWord;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=dat_header.Files;
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT Count(*) AS cnumber FROM datfiles;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        Result:=Query.FieldByName('cnumber').AsInteger;
+      END ELSE Result:=0;
+      Query.Close;
+    END;
+  END;
+
+FUNCTION GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringList;
+  VAR
+    i:LongWord;
+    where:String;
+    where_ext: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 (Pos(dat_files[i].Extension,ext)>0) ) 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);
+              IF AppSettings.FilenumbersAsHex THEN
+                Result[High(Result)]:=dat_files[i].FileNameHex
+              ELSE
+                Result[High(Result)]:=dat_files[i].FileName;
+            END;
+          END ELSE BEGIN
+            SetLength(Result,Length(Result)+1);
+            IF AppSettings.FilenumbersAsHex THEN
+              Result[High(Result)]:=dat_files[i].FileNameHex
+            ELSE
+              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 ';
+        IF Pos(',',ext)>0 THEN BEGIN
+          i:=1;
+          where_ext:='';
+          WHILE i<Length(ext) DO BEGIN
+            IF Length(where_ext)>0 THEN where_ext:=where_ext+' OR ';
+            where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")';
+            i:=i+5;
+          END;
+          where:=where+'('+where_ext+')';
+        END ELSE BEGIN
+          where:=where+'(extension="'+ext+'")';
+        END;
+      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;
+    header_pc,header_mac:Boolean;
+  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));
+    header_pc:=True;
+    header_mac:=True;
+    FOR i:=0 TO High(dat_header.Ident) DO BEGIN
+      IF dat_header.Ident[i]<>header_ident1_pc[i] THEN BEGIN
+        header_pc:=False;
+      END;
+      IF dat_header.Ident[i]<>header_ident1_mac[i] THEN BEGIN
+        header_mac:=False;
+      END;
+    END;
+    IF NOT (header_pc OR header_mac) THEN BEGIN
+      Result:=False;
+      Exit;
+    END ELSE BEGIN
+      IF (header_pc AND NOT header_mac) THEN
+        dat_os_mac:=False
+      ELSE
+        IF (NOT header_pc AND header_mac) THEN
+          dat_os_mac:=True
+        ELSE BEGIN
+          Result:=False;
+          Exit;
+        END;
+    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;
+      dat_files[i].FileNameHex:=IntToHex(i,4)+'-'+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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),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)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      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 LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+  VAR
+    i:Byte;
+    raw_info:TRawInfo;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      raw_info:=GetRawInfo(fileid,dat_offset);
+      LoadRawFile(fileid,dat_offset,raw_info.raw_addr,raw_info.raw_size,raw_info.loc_sep,target);
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Result:=True;
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT rawinfo.loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenReadWrite)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),fmOpenReadWrite);
+      filestream.Seek(rawinfo.raw_addr,soFromBeginning);
+      filestream.Write(target^,rawinfo.raw_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;
+    rawlist:TRawList;
+  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
+        rawlist:=GetRawList(fileid);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR i:=0 TO High(rawlist) DO BEGIN
+            ExportRawFile(fileid,rawlist[i].src_offset,path+'\'+GetWinFileName(filename));
+          END;
+        END;
+      END;
+    END;
+  END;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringList;
+  VAR
+    start,len:Word;
+  BEGIN
+    SetLength(Result, 0);
+    start:=1;
+    WHILE PosEx(delimiter,_string,start)>0 DO BEGIN
+      len:=PosEx(delimiter,_string,start)-start;
+      SetLength(Result, Length(Result)+1);
+      Result[High(Result)]:=MidStr(_string,start,len);
+      start:=start+len+1;
+    END;
+    SetLength(Result, Length(Result)+1);
+    Result[High(Result)]:=MidStr(_string,start,Length(_string)-start+1);
+  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.29a2/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,116 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.29a';
+  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;
+    FileNameHex: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];
+    FilenumbersAsHex:Boolean;
+  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;
+
+  TRawInfo=RECORD
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+    loc_sep:Boolean;
+  END;
+  TRawList=Array OF TRawInfo;
+
+VAR
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_os_mac:Boolean=False;
+  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_pc: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_ident1_mac:Array[0..$13] OF Byte=
+      ($61,$30,$C1,$23,$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.29a2/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,218 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, Dialogs, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset: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, Unit9_data_structures;
+
+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;
+
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    SetLength(data, GetRawInfo(fileid, dat_offset).raw_size);
+    LoadRawFileByIDOffset(fileid,dat_offset,@data[0]);
+    IF FileExists(filename+'.raw0x'+IntToHex(dat_offset,8)) THEN BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd);
+    END ELSE BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),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,$44,rawpos,Length(data),False,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.29a2/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Caption = 'Preview'
+  ClientHeight = 473
+  ClientWidth = 472
+  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.29a2/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit5_preview.pas	(revision 8)
@@ -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(GetFilesCount)+')');
+    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:=GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    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.29a2/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,406 @@
+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;
+  VAR
+    img_addr:LongWord;
+  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);
+    IF NOT dat_os_mac THEN
+      LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr)
+    ELSE
+      LoadDatFilePart(fileid,$A0,SizeOf(img_addr),@img_addr);
+
+    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);
+
+    IF NOT dat_os_mac THEN
+      LoadRawFile(fileid,$9C,img_addr,Result.datasize,dat_os_mac,@Result.imgdata[0])
+    ELSE
+      LoadRawFile(fileid,$A0,img_addr,Result.datasize,dat_os_mac,@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.29a2/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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 = 'MIP Mapping'
+      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.29a2/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit7_txmpreplace.pas	(revision 8)
@@ -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:=GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+
+    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:=GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+      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(GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]));
+      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.29a2/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.29a2/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.29a2/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,385 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 555
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 555
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+    ExplicitHeight = 423
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 555
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    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 = 450
+      Width = 483
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitTop = 375
+    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 = []
+      OnKeyUp = hexKeyUp
+      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 value_viewer: TWrapGrid
+      Left = 0
+      Top = 218
+      Width = 483
+      Height = 232
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      PopupMenu = value_viewer_context
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+    object VST: TVirtualStringTree
+      Left = 0
+      Top = 458
+      Width = 483
+      Height = 97
+      Align = alBottom
+      AnimationDuration = 0
+      AutoExpandDelay = 300
+      BiDiMode = bdLeftToRight
+      Colors.UnfocusedSelectionColor = clGradientActiveCaption
+      Colors.UnfocusedSelectionBorderColor = clGradientActiveCaption
+      Ctl3D = True
+      DragOperations = []
+      DrawSelectionMode = smBlendedRectangle
+      EditDelay = 200
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      Header.AutoSizeIndex = 0
+      Header.Font.Charset = DEFAULT_CHARSET
+      Header.Font.Color = clWindowText
+      Header.Font.Height = -11
+      Header.Font.Name = 'Tahoma'
+      Header.Font.Style = []
+      Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoVisible]
+      Header.PopupMenu = VTHPopup
+      Header.Style = hsFlatButtons
+      HintAnimation = hatNone
+      HintMode = hmTooltip
+      Indent = 14
+      ParentBiDiMode = False
+      ParentCtl3D = False
+      ParentFont = False
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 2
+      TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning]
+      TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowRoot, toShowTreeLines, toShowVertGridLines, toUseBlendedImages]
+      TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect]
+      OnDblClick = VSTDblClick
+      OnFocusChanged = VSTFocusChanged
+      OnGetText = VSTGetText
+      OnHeaderDragged = VSTHeaderDragged
+      Columns = <
+        item
+          MaxWidth = 300
+          MinWidth = 100
+          Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 0
+          Spacing = 20
+          Width = 150
+          WideText = 'Name'
+          WideHint = 'Name of the item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 1
+          Spacing = 20
+          Width = 85
+          WideText = 'Offset'
+          WideHint = 'Offset of the data-item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 75
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 2
+          Width = 75
+          WideText = 'Type'
+          WideHint = 'Data type of the item.'
+        end
+        item
+          MaxWidth = 250
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 3
+          Width = 100
+          WideText = 'Value'
+          WideHint = 'Value of the item.'
+        end
+        item
+          MaxWidth = 400
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 4
+          Width = 400
+          WideText = 'Description'
+        end>
+      WideDefaultText = ''
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 555
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Bevel1: TBevel
+      Left = 0
+      Top = 491
+      Width = 150
+      Height = 6
+      Align = alBottom
+      Style = bsRaised
+      ExplicitTop = 359
+    end
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 388
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 388
+      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 = 497
+      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
+  object VTHPopup: TVTHeaderPopupMenu
+    OnColumnChange = VTHPopupColumnChange
+    Left = 200
+    Top = 496
+  end
+end
Index: /oup/releases/0.29a2/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,869 @@
+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, Math,
+  VirtualTrees, VTHeaderPopup;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    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;
+    VST: TVirtualStringTree;
+    VTHPopup: TVTHeaderPopupMenu;
+    procedure VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex);
+    procedure VSTDblClick(Sender: TObject);
+    procedure VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+      const Column: TColumnIndex; Visible: Boolean);
+    procedure VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+      OldPosition: Integer);
+    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE LoadDat(_fileid:LongWord);
+    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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    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 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, Unit13_rawedit;
+VAR
+  fileid:LongWord;
+
+TYPE
+  PNodeData = ^TNodeData;
+  TNodeData = record
+    Caption:String;
+    Offset:LongInt;
+    DataType:Word;
+    Value:String;
+    Description:String;
+  end;
+
+
+function AddVSTEntry(AVST:TCustomVirtualStringTree; ANode:PVirtualNode; ARecord:TNodeData):PVirtualNode;
+  var
+    data:PNodeData;
+  begin
+    Result:=AVST.AddChild(ANode);
+    data:=AVST.GetNodeData(Result);
+    AVST.ValidateNode(Result,False);
+    data^:=ARecord;
+  end;
+
+
+
+PROCEDURE TForm8.LoadDat(_fileid:LongWord);
+  VAR
+    i:LongWord;
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF GetFileIDByName(list.Items.Strings[i])=fileid THEN BEGIN
+            list.ItemIndex:=i;
+            Exit;
+          END;
+        END;
+      END;
+    END;
+    fileid:=_fileid;
+    FOR i:=0 TO list.Count-1 DO
+      IF GetFileIDByName(list.Items.Strings[i])=fileid THEN
+        list.ItemIndex:=i;
+    Self.ClearStructViewer;
+    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; 
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(GetFilesCount)+')');
+    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
+    LoadDat(GetFileIDByName(list.Items.Strings[list.ItemIndex]));
+  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]);
+      11: Result:='0x'+IntToHex(GetRawInfo(fileid,offset).raw_addr,8);
+      12: Result:=FormatNumber(hex.data[offset+1]+hex.data[offset+2]*256+hex.data[offset+3]*256*256,5,'0');
+      13: Result:=IntToStr(hex.data[offset]);
+      14: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256);
+      15: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256);
+      16: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256);
+      1000..9999: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-1000 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Result:=Result+'.';
+          END;
+        END;
+      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;
+  VAR
+    i,j:LongWord;
+    pdata: PNodeData;
+    data: TNodeData;
+    node: PVirtualNode;
+    structs: TStructDef;
+  BEGIN
+    VST.BeginUpdate;
+    IF VST.RootNodeCount=0 THEN BEGIN
+      structs:=LoadStructureDefinition(fileid);
+      IF structs.data THEN BEGIN
+        IF Length(structs.Global)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Global) DO BEGIN
+            data.Caption:=structs.Global[i].name;
+            data.Offset:=structs.Global[i].offset;
+            data.DataType:=structs.Global[i].datatype;
+            data.Value:=GetValue(structs.Global[i].datatype, structs.Global[i].offset);
+            data.Description:=structs.Global[i].description;
+            AddVSTEntry(VST, nil, data);
+          END;
+        END;
+        IF Length(structs.Subs)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Subs) DO BEGIN
+            WITH structs.Subs[i] DO BEGIN
+              IF Length(Entries)>0 THEN BEGIN
+                IF Pos('#',SubName)>0 THEN BEGIN
+                  data.Offset:=HexToLong(MidStr(SubName, Pos('#',SubName)+1, 8));
+                  data.Value:=MidStr(SubName, PosEx('#',SubName,Pos('#',SubName)+1)+1, 8);
+                  data.Caption:=MidStr(SubName, 1, Pos('#',SubName)-1);
+                END ELSE BEGIN
+                  data.Caption:=SubName;
+                  data.Offset:=0;
+                  data.Value:='';
+                END;
+                data.DataType:=0;
+                data.Description:='';
+                node:=AddVSTEntry(VST, nil, data);
+                FOR j:=0 TO High(Entries) DO BEGIN
+                  data.Caption:=Entries[j].name;
+                  data.Offset:=Entries[j].offset;
+                  data.DataType:=Entries[j].datatype;
+                  data.Value:=GetValue(Entries[j].datatype, Entries[j].offset);
+                  data.Description:=Entries[j].description;
+                  AddVSTEntry(VST, node, data);
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      IF VST.RootNodeCount>0 THEN
+        VST.FocusedNode:=VST.GetFirst;
+    END ELSE BEGIN
+      Node:=VST.GetFirst;
+      WHILE Assigned(Node) DO BEGIN
+        pdata:=VST.GetNodeData(Node);
+        IF pdata.DataType>0 THEN
+          pdata.Value:=GetValue(pdata.Datatype, pdata.Offset);
+        Node:=VST.GetNext(Node);
+      END;
+    END;
+    VST.EndUpdate;
+  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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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;
+    VST.NodeDataSize:=SizeOf(TNodeData);
+    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;
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  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);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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;
+  BEGIN
+    VST.Clear;
+  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.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos;
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm8.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm8.hexSelectionChanged(Sender: TObject);
+  VAR
+    selstart:Integer;
+    i,j:Word;
+
+    node:PVirtualNode;
+    pdata:PNodeData;
+  BEGIN
+    IF hex.DataSize>0 THEN BEGIN
+      selstart:=hex.SelStart;
+      IF VST.RootNodeCount>0 THEN BEGIN
+        Node:=VST.GetFirst;
+        WHILE Assigned(Node) DO BEGIN
+          pdata:=VST.GetNodeData(Node);
+          IF pdata.DataType>0 THEN BEGIN
+            IF ((selstart-pdata.Offset)<GetTypeDataLength(pdata.DataType)) AND ((selstart-pdata.Offset)>=0) THEN BEGIN
+              VST.FocusedNode:=Node;
+              VST.Selected[Node]:=True;
+              Break;
+            END;
+          END;
+          Node:=VST.GetNext(Node);
+        END;
+      END;
+    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.VSTDblClick(Sender: TObject);
+  var
+    node:PVirtualNode;
+    nodedata:PNodeData;
+  begin
+    if VST.FocusedColumn=3 then begin
+      node:=VST.FocusedNode;
+      nodedata:=VST.GetNodeData(node);
+
+      IF NOT (nodedata.datatype IN [11,12]) THEN BEGIN
+        Form12.MakeVarInput(nodedata.Caption,nodedata.offset,nodedata.datatype,nodedata.value,Self);
+      END ELSE BEGIN
+        IF nodedata.DataType=11 THEN BEGIN
+          IF GetRawInfo(fileid,nodedata.offset).raw_size>0 THEN BEGIN
+            IF Form1.open_child('rawedit') THEN BEGIN
+              TForm13(Form1.ActiveMDIChild).LoadRaw(GetRawInfo(fileid,nodedata.offset));
+            END;
+          END;
+        END;
+        IF nodedata.DataType=12 THEN BEGIN
+          IF (StrToInt(nodedata.Value)<GetFilesCount) AND
+              (StrToInt(nodedata.Value)>0) AND
+              (StrToInt(nodedata.Value)<>fileid) THEN BEGIN
+            IF GetFileInfo(StrToInt(nodedata.Value)).Size>0 THEN BEGIN
+              IF Form1.open_child('binedit') THEN BEGIN
+                TForm8(Form1.ActiveMDIChild).LoadDat(StrToInt(nodedata.Value));
+              END;
+            END ELSE BEGIN
+              ShowMessage('Linked filed is a zero-byte-file');
+            END;
+          END;
+        END;
+      END;
+
+    end;
+  end;
+
+procedure TForm8.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex);
+  var
+    data:PNodeData;
+  begin
+    data:=VST.GetNodeData(node);
+    IF data.DataType>0 THEN BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+GetTypeDataLength(data.DataType)-1;
+    END ELSE BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+HexToLong(data.Value)-1;
+    END;
+end;
+
+procedure TForm8.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+  var
+    data:PNodeData;
+  begin
+    data := Sender.GetNodeData(Node);
+    CellText := '';
+    if TextType = ttNormal then begin
+      case Column of
+        0: CellText := data.Caption;
+        1:
+          if data.DataType>0 then
+            CellText := '0x'+IntToHex(data.Offset,8);
+        2:
+          if data.DataType>0 then
+            CellText := GetDataType(data.DataType);
+        3:
+          CellText := GetValue(data.DataType, data.Offset);
+        4:
+          CellText := data.Description;
+      end;
+    end;
+  end;
+
+procedure TForm8.VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+  OldPosition: Integer);
+  begin
+    if Sender.Columns.Items[column].Position<1 then
+      Sender.Columns.Items[column].Position:=OldPosition;
+  end;
+
+procedure TForm8.VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+  const Column: TColumnIndex; Visible: Boolean);
+  begin
+    if column=0 then
+      TVirtualStringTree(Sender).Header.Columns.Items[column].Options:=TVirtualStringTree(Sender).Header.Columns.Items[column].Options+[coVisible];
+  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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+
+END.
Index: /oup/releases/0.29a2/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.29a2/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.29a2/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,501 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, ABSMain, DB, ABSDecUtil, Classes, Unit3_data, Dialogs, StrUtils;
+
+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
+                      // 11    : raw-addr
+                      // 12    : dat-file-ID
+                      // 13..16: Signed Integer[1..4]
+                      // 1000..9999: Unused data[0-8999]
+                      // 10000+: string[0+]
+      description:String;
+    END;
+  TStructDefSub=RECORD
+      SubName:String;
+      Entries:Array OF TStructure_entry;
+    END;
+  TStructDef=RECORD
+      Data:Boolean;
+      Global:Array OF TStructure_entry;
+      Subs:Array OF TStructDefSub;
+    END;
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+
+VAR
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+
+
+IMPLEMENTATION
+USES Unit2_functions, Forms;
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      12: Result:=4;
+      13..16: Result:=datatype-12;
+      1000..9999: Result:=datatype-1000;
+      10000..65535: Result:=datatype-10000;
+    END;
+  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';
+      11: Result:='Raw-Address';
+      12: Result:='.dat-file-ID';
+      13..16: Result:='SignedInt'+IntToStr((typeid-12)*8);
+      1000..9999: Result:='Unused('+IntToStr(typeid-1000)+')';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  VAR
+    i:LongWord;
+    raw_list:TRawList;
+  BEGIN
+    raw_list:=GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    FOR i:=0 TO High(raw_list) DO BEGIN
+      IF raw_list[i].src_offset=dat_offset THEN BEGIN
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Result.loc_sep:=raw_list[i].loc_sep;
+        Break;
+      END;
+    END;
+  END;
+
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+  VAR
+    i:LongWord;
+    Query:TABSQuery;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=0 TO High(RawListHandlers) DO
+        IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN
+          IF RawListHandlers[i].needed THEN BEGIN
+            Result:=RawListHandlers[i].Handler(fileid);
+            Break;
+          END ELSE
+            Break;
+    END ELSE BEGIN
+      SetLength(Result,0);
+      Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i].src_id:=fileid;
+          Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger;
+          Result[i].raw_addr:=0;
+          Result[i].raw_size:=Query.FieldByName('size').AsInteger;
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*4;
+        LoadDatFilePart(fileid,$20+i*4,4,@link);
+        Result[i].raw_addr:=link;
+        Result[i].raw_size:=0{????????????????????????????????};
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION AKVA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*$74+$24;
+        LoadDatFilePart(fileid,$20+i*$74+$24,4,@link);
+        Result[i].raw_addr:=link;
+        LoadDatFilePart(fileid,$20+i*$74+$28,4,@link);
+        Result[i].raw_size:=link;
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$0C,4,@link);
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$40,4,@datasize);
+      LoadDatFilePart(fileid,$44,4,@link);
+      Result[0].src_offset:=$44;
+    END ELSE BEGIN
+      LoadDatFilePart(fileid,$10,4,@datasize);
+      LoadDatFilePart(fileid,$14,4,@link);
+      Result[0].src_offset:=$14;
+    END;
+    SetLength(Result,1);
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=False;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,link:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    LoadDatFilePart(fileid,$18,4,@baselink);
+    LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      LoadDatFilePart(fileid,$20+(links-1)*4,4,@link);
+      SetLength(data,link+1024);
+      LoadRawFile(fileid,$1C,baselink,link+1024,False,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[link+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=link+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    LoadDatFilePart(fileid,$182,1,@tempb);
+    LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    LoadDatFilePart(fileid,$183,1,@tempb);
+    LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    LoadDatFilePart(fileid,$184,1,@tempb);
+    LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    LoadDatFilePart(fileid,$185,1,@tempb);
+    LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    LoadDatFilePart(fileid,$186,1,@tempb);
+    LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    LoadDatFilePart(fileid,$187,1,@tempb);
+    LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    LoadDatFilePart(fileid,$154,2,@tempw);
+    LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    LoadDatFilePart(fileid,$138,4,@templ);
+    LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link_pc:LongWord;
+    link_mac:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    LoadDatFilePart(fileid,$9C,4,@link_pc);
+    LoadDatFilePart(fileid,$A0,4,@link_mac);
+    CASE storetype OF
+      0,1,2: datasize:=x*y*2;
+      8: datasize:=x*y*4;
+      9: datasize:=x*y DIV 2;
+    END;
+    SetLength(Result,1);
+    IF NOT dat_os_mac THEN BEGIN
+      Result[0].src_offset:=$9C;
+      Result[0].raw_addr:=link_pc
+    END ELSE BEGIN
+      Result[0].src_offset:=$A0;
+      Result[0].raw_addr:=link_mac;
+    END;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+  VAR
+    i:LongWord;
+    current_type:Byte; //0: Global, 1: Undynamic, 2: Dynamic
+    current_base,current_package,current_package_size:LongWord;
+    packages:LongWord;
+    deffile:Text;
+    structentry:TStructure_Entry;
+    fields:TStringList;
+    filename:String;
+    ext:String[4];
+    temps:String;
+    data:TData;
+  BEGIN
+    SetLength(Result.Global,0);
+    SetLength(Result.Subs,0);
+    Result.Data:=False;
+    ext:=GetFileInfo(fileid).Extension;
+    filename:=ExtractFilePath(Application.ExeName)+'\StructDefs\'+ext+'.txt';
+    IF FileExists(filename) THEN BEGIN
+      data:=LoadDatFile(fileid);
+      AssignFile(deffile,filename);
+      Reset(deffile);
+      current_type:=0;
+      Result.Data:=True;
+      IF NOT EoF(deffile) THEN BEGIN
+        ReadLn(deffile,temps);
+        WHILE NOT EoF(deffile) DO BEGIN
+          ReadLn(deffile,temps);
+          IF Length(temps)>0 THEN BEGIN
+            IF temps[1]='*' THEN BEGIN
+              fields:=Explode(temps,'#');
+              CASE Length(fields) OF
+                1: BEGIN
+                     current_type:=1;
+                     current_base:=0;
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                   END;
+                2: BEGIN
+                     current_type:=1;
+                     current_base:=HexToLong(fields[1]);
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                   END;
+                5: BEGIN
+                     current_type:=2;
+                     current_base:=HexToLong(fields[1]);
+                     current_package:=0;
+                     current_package_size:=StrToInt(fields[4]);
+                     CASE StrToInt(fields[3]) OF
+                       1: packages:=data[HexToLong(fields[2])];
+                       2: packages:=data[HexToLong(fields[2])]+data[HexToLong(fields[2])+1]*256;
+                       4: packages:=data[HexToLong(fields[2])]+data[HexToLong(fields[2])+1]*256+data[HexToLong(fields[2])+2]*256*256+data[HexToLong(fields[2])+3]*256*256*256;
+                     END;
+                     SetLength(Result.Subs, Length(Result.Subs)+packages);
+                     FOR current_package:=0 TO packages-1 DO BEGIN
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubName:=
+                           MidStr(fields[0],2,Length(fields[0])-1)+'['+IntToStr(current_package)+']'+
+                           '#'+IntToHex(current_base+current_package*current_package_size,8)+
+                           '#'+IntToHex(current_package_size,8);
+                     END;
+                   END;
+              END;
+            END ELSE BEGIN
+              fields:=Explode(temps,#9);
+              IF (Length(fields)=3) OR (Length(fields)=4) THEN BEGIN
+                structentry.name:=fields[0];
+                structentry.datatype:=StrToInt(fields[2]);
+                IF Length(fields)=4 THEN
+                  structentry.description:=fields[3]
+                ELSE
+                  structentry.description:='';
+                IF current_type IN [0,1] THEN BEGIN
+                  structentry.offset:=HexToLong(fields[1])+current_base;
+                  IF Length(Result.Subs)=0 THEN BEGIN
+                    SetLength(Result.Global,Length(Result.Global)+1);
+                    Result.Global[High(Result.Global)]:=structentry;
+                  END ELSE BEGIN
+                    SetLength(Result.Subs[High(Result.Subs)].Entries,Length(Result.Subs[High(Result.Subs)].Entries)+1);
+                    Result.Subs[High(Result.Subs)].Entries[High(Result.Subs[High(Result.Subs)].Entries)]:=structentry;
+                  END;
+                END ELSE BEGIN
+                  FOR current_package:=0 TO packages-1 DO BEGIN
+                    structentry.offset:=current_base+current_package*current_package_size+HexToLong(fields[1]);
+                    WITH Result.Subs[High(Result.Subs)-packages+current_package+1] DO BEGIN
+                      SetLength(Entries,Length(Entries)+1);
+                      Entries[High(Entries)]:=structentry;
+                    END;
+                  END;
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      CloseFile(deffile);
+    END;
+  END;
+
+
+BEGIN
+//  InsertRawListHandler('AGDB',True,AGDB);
+  InsertRawListHandler('AKVA',True,AKVA);
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.29a2/todo.txt
===================================================================
--- /oup/releases/0.29a2/todo.txt	(revision 8)
+++ /oup/releases/0.29a2/todo.txt	(revision 8)
@@ -0,0 +1,156 @@
+Unit10 unabhängig, funktionsweise wiederherstellen
+Schreibt auch die dat_files[] etc
+Benutzt die *globalen* dat_stream/raw_stream und keine MemCopy
+
+-Datei von einem Tool in andrem Tool öffnen
+
+-TXMPReplace: Zugriff über Unit2
+
+
+-SELECT [src_id],MIN(datfiles.[name]),SUM(rawmap.[size]) FROM rawmap INNER  JOIN datfiles ON datfiles.[id]=[src_id] GROUP BY [src_id] ORDER BY [src_id] ASC
+
+-Extrahier-Ordner-Option (mit Platzhalter für .dat-Name)
+
+-HELP.hlp
+-About
+
+-BinEdit: Zusatzfunktionen wie: Suche, 
+-BinEdit: Bild/Menu/Button irgendwas zum speichern
+
+-Extractor: Wohin?
+
+-FileCompare: Ergebnis=Tabelle, jede Zeile eine differenz-addresse, spalten = werte an addr. für compared files
+
+-TXMP-Replace: MultiReplace
+
+-Move-Freischalter (Mindestlvl eingabe)
+
+-Löschen einer Datei auf die gelinkt wird: Liste der Links und sicherheitsfrage
+
+-Filebox-Context: Extract etc
+
+-DAT geladen -> Meldung oder sogar "what to do next?"
+-SSG: Levels extrahieren?
+-Pierre: Wie Char-Anims, Char-Models, Levels extrahieren?
+-Language-Files?
+-STRG+C auf Dateilisten etc für kopieren des Namens
+
+-REPACKING: testen lvl0: 690-collisions.txmp einbauen, script: collisions-zeug
+
+#################################################################
+##########                 File-Types                  ##########
+#################################################################
+(3CLA)
+ABNA
+AGDB
+AGQC
+AGQG
+(AGQM)
+AGQR
+AISA
+AITR
+(AIWA)
+AKAA
+AKBA
+AKBP
+AKDA
+AKEV
+AKOT
+AKVA
+BINA
+CBPI
+CBPM
+CONS
+CRSA
+DOOR
+DPge
+(EDIA)
+ENVP
+FILM
+(FXLR)
+(GMAN)
+HPge
+IDXA
+IGHH
+IGPA
+IGPG
+IGSA
+IGSt
+Impt
+IPge
+KeyI
+M3GA
+M3GM
+(M3TA)
+Mtrl
+(NMSA)
+OBAN
+OBDC
+(OBLS)
+OBOA
+OFGA
+ONCC
+ONCP
+ONCV
+ONFA
+ONGS
+ONIA
+ONLD
+ONLV
+ONMA
+ONOA
+ONSA
+ONSK
+ONTA
+ONVL
+ONWC
+OPge
+OSBD
+OTIT
+OTLF
+PLEA
+PNTA
+PSpc
+PSpL
+PSUI
+QTNA
+(QUDA)
+SNDD
+StNA
+SUBT
+(TMFA)
+(TMRA)
+TRAC
+TRAM
+TRAS
+TRBS
+TRCM
+(TRFT)
+TRGA
+TRGE
+TRIA
+TRIG
+TRMA
+TRSC
+TRTA
+TSFF
+TSFL
+TSFT
+TSGA
+TStr
+TURR
+TXAN
+TXCA
+TXMA
+TXMB
+TXMP
+(TXPC)
+TxtC
+(UUEA)
+(UVDL)
+VCRA
+WMCL
+WMDD
+WMM_
+WMMB
+WPge
Index: /oup/releases/0.29a3/StructDefs/AISA.txt
===================================================================
--- /oup/releases/0.29a3/StructDefs/AISA.txt	(revision 8)
+++ /oup/releases/0.29a3/StructDefs/AISA.txt	(revision 8)
@@ -0,0 +1,9 @@
+AI Character Setup Array
+
+File ID	$00	12
+Level ID	$04	4
+Unused	$08	1022
+Packages	$1E	2
+
+*AIs		$20	$1E	2	352
+Intro func	$50	10032
Index: /oup/releases/0.29a3/StructDefs/ONCC.txt
===================================================================
--- /oup/releases/0.29a3/StructDefs/ONCC.txt	(revision 8)
+++ /oup/releases/0.29a3/StructDefs/ONCC.txt	(revision 8)
@@ -0,0 +1,58 @@
+Oni character class
+TXMP link	$28	12	Shadow texture
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use an hypo
+Hurt light sound	$98	10032	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	10032	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	10032	Reference to an OSBD file of level 0
+Death sound	$F8	10032	Reference to an OSBD file of level 0
+Taunt sound query	$2B0	10	00 = not used; 64 = used
+"Whos there?" sound query	$2B1	10	00 = not used; 64 = used
+"I see you" sound query	$2B2	10	00 = not used; 64 = used
+"You lose" sound query	$2B3	10	00 = not used; 64 = used
+"Where are you?" sound query	$2B4	10	00 = not used; 64 = used
+"Why is this happenung?" sound query	$2B5	10	00 = not used; 64 = used
+Superpunch sound query	$2B6	10	00 = not used; 64 = used
+Superkick sound query	$2B7	10	00 = not used; 64 = used
+Super3 sound query	$2B8	10	00 = not used; 64 = used
+Super4 sound query	$2B9	10	00 = not used; 64 = used
+Taunt sound	$2BC	10032	Reference to a SNDD file of level 0
+"Whos there?" sound	$2DC	10032	Reference to a SNDD file of level 0
+"I see you" sound	$2FC	10032	Reference to a SNDD file of level 0
+"You lose" sound	$31C	10032	Reference to a SNDD file of level 0
+"Where are you?" sound	$33C	10032	Reference to a SNDD file of level 0
+"Why is this happenung?" sound	$35C	10032	Reference to a SNDD file of level 0
+Superpunch sound	$37C	10032	Reference to a SNDD file of level 0
+Superkick sound	$39C	10032	Reference to a SNDD file of level 0
+Super3 sound	$3BC	10032	Reference to a SNDD file of level 0
+Super4 sound	$3DC	10032	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV link	$434	12	Character varient link
+ONCP link	$438	12	Character particle array link; useless?
+ONIA link	$43C	12	Character impact array link; useless?
+Unknown	$444	10016	Maybe the weight of the character?
+Footstep walk impact	$454	10128	Reference to the a Impt file of level 0
+Footstep run impact	$4D6	10128	Reference to the a Impt file of level 0
+Footstep crouch impact	$558	10128	Reference to the a Impt file of level 0
+Fall slide impact	$5DA	10128	Reference to the a Impt file of level 0
+Fall land impact	$65C	10128	Reference to the a Impt file of level 0
+Fall land hard impact	$6DE	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$760	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$7E2	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$864	10128	Reference to the a Impt file of level 0
+Footstep turn impact	$8E6	10128	Reference to the a Impt file of level 0
+Footstep run start impact	$968	10128	Reference to the a Impt file of level 0
+Footstep single step impact	$9EA	10128	Reference to the a Impt file of level 0
+Footstep run stop impact	$A6C	10128	Reference to the a Impt file of level 0
+Footstep walk stop impact	$AEE	10128	Reference to the a Impt file of level 0
+Footstep run sprint impact	$B70	10128	Reference to the a Impt file of level 0
+Unknown	$BF4	10064	special death particles; only the mad bomber use it
+TRBS link	$C3C	8	Body set link
+TRMA link	$C40	8	Texture map array link
+CBPM link	$C44	8	Body part material link
+CBPI link	$C48	8	Body part impact link
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC link	$C88	8	Animation collection link
+TRSC link	$C8C	8	Screen (aiming) collection link
Index: /oup/releases/0.29a3/StructDefs/SUBT.txt
===================================================================
--- /oup/releases/0.29a3/StructDefs/SUBT.txt	(revision 8)
+++ /oup/releases/0.29a3/StructDefs/SUBT.txt	(revision 8)
@@ -0,0 +1,5 @@
+Subtitles
+ID	$00	4	ID of this file
+LevelID	$04	8	ID of the level this file is in
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Subtitle count	$1C	4	Number of subtitles in this file
Index: /oup/releases/0.29a3/StructDefs/TRAM.txt
===================================================================
--- /oup/releases/0.29a3/StructDefs/TRAM.txt	(revision 8)
+++ /oup/releases/0.29a3/StructDefs/TRAM.txt	(revision 8)
@@ -0,0 +1,49 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	8	Flags; It seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	8	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	8	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	2	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	10016	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	6	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
Index: /oup/releases/0.29a3/StructDefs/TXAN.txt
===================================================================
--- /oup/releases/0.29a3/StructDefs/TXAN.txt	(revision 8)
+++ /oup/releases/0.29a3/StructDefs/TXAN.txt	(revision 8)
@@ -0,0 +1,14 @@
+Texture Animation
+
+File ID	$00	12	File ID of this file
+Level Number	$04	4
+Unused	$08	1012
+
+Loop speed	$14	2
+Unknown	$16	2
+Unknown	$18	2
+Unused	$1A	1002
+Number of images	$1C	4
+
+*Packages		$20	$1C	4	4
+Image	$0	12
Index: /oup/releases/0.29a3/StructDefs/TXMP.txt
===================================================================
--- /oup/releases/0.29a3/StructDefs/TXMP.txt	(revision 8)
+++ /oup/releases/0.29a3/StructDefs/TXMP.txt	(revision 8)
@@ -0,0 +1,13 @@
+Texture
+ID	$00	12	ID of this file
+LevelID	$04	8	ID of the level this file is in
+FileName	$08	10128	
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	12	Link to the TXAN-file (if this TXMP is the first image of an animation)
+TXMP-Link	$98	12	Link to another TXMP-file
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
Index: /oup/releases/0.29a3/blubb.txt
===================================================================
--- /oup/releases/0.29a3/blubb.txt	(revision 8)
+++ /oup/releases/0.29a3/blubb.txt	(revision 8)
@@ -0,0 +1,6 @@
+___FILEINDEX___.txt
+
+
+TXMP:
+MipMapping: Bit0=an/aus
+ColorDepth: Bit0=??AnimationPic??, Bit1=shade vertex, Bit2=transparency, Bit4=16bit, Bit5=32bit
Index: /oup/releases/0.29a3/changelog.txt
===================================================================
--- /oup/releases/0.29a3/changelog.txt	(revision 8)
+++ /oup/releases/0.29a3/changelog.txt	(revision 8)
@@ -0,0 +1,94 @@
+OniUnPacker v0.29a
+------------------
++Little changes in StructureDefs
+
+OniUnPacker v0.29a
+------------------
++New StructureViewer
++New StructureTypes: 12=.dat-file-ID, 13..16=SignedInteger, 1000..9999=Unused data
++Dynamic Structures (look at TXAN-files or AISA-files for examples)
++File-type associations (.dat, .oldb, .opf) with OUP possible
++File IDs as Hex
+
+OniUnPacker v0.28a
+------------------
++StructureDefinitions as separate txt-files
++Minor bugfixes
++Ctrl+C for Hex-fields
+
+OniUnPacker v0.27a
+------------------
++Added MAC-file support
++Added StructureDefs for ONCCs / TRAMs (thanks to SSG)
+
+OniUnPacker v0.26a
+------------------
++Fixed some bugs again ;)
+
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.29a3/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.29a3/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.29a3/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,184 @@
+﻿<?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 Name="UnitInitSeq">True</Compiler>
+			<Compiler Name="LocalPInvoke">True</Compiler>
+			<Compiler Name="CodePage"></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 Name="GenerateHpps">False</Linker>
+		</Linker>
+		<Directories>
+			<Directories Name="OutputDir">exe</Directories>
+			<Directories Name="UnitOutputDir">dcu</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 Name="Debug Symbols Search Path"></Parameters>
+			<Parameters Name="LoadAllSymbols">True</Parameters>
+			<Parameters Name="LoadUnspecifiedSymbols">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>
+		<Language>
+			<Language Name="ActiveLang"></Language>
+			<Language Name="ProjectLang">$00000000</Language>
+			<Language Name="RootDir"></Language>
+		</Language>  
+    <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.29a3/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.29a3/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.29a3/src/OniUnPacker.cfg	(revision 8)
@@ -0,0 +1,40 @@
+-$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
+-E"exe"
+-N0"dcu"
+-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.29a3/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.29a3/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.29a3/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,31 @@
+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},
+  Unit13_rawedit in 'Unit13_rawedit.pas' {Form13},
+  Unit14_settings in 'Unit14_settings.pas' {Form14},
+  ftypesAPI in 'TFileTypeRegistration\ftypesAPI.pas';
+
+{$R *.res}
+{$R icon2.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.CreateForm(TForm12, Form12);
+  Application.CreateForm(TForm14, Form14);
+  Application.Run;
+END.
Index: /oup/releases/0.29a3/src/TFileTypeRegistration/IsAdmin.inc
===================================================================
--- /oup/releases/0.29a3/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
+++ /oup/releases/0.29a3/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
@@ -0,0 +1,90 @@
+function GetAdminSid: PSID;
+const
+  // bekannte SIDs ... (WinNT.h)
+  SECURITYNTAUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
+  // bekannte RIDs ... (WinNT.h)
+  SECURITYBUILTINDOMAINRID: DWORD = $00000020;
+  DOMAINALIASRIDADMINS: DWORD = $00000220;
+begin
+  Result := nil;
+  AllocateAndInitializeSid(SECURITYNTAUTHORITY,
+    2,
+    SECURITYBUILTINDOMAINRID,
+    DOMAINALIASRIDADMINS,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    Result);
+end;
+
+function IsAdmin: LongBool;
+var
+  TokenHandle      : THandle;
+  ReturnLength     : DWORD;
+  TokenInformation : PTokenGroups;
+  AdminSid         : PSID;
+  Loop             : Integer;
+  wv               : TOSVersionInfo;
+begin
+  wv.dwOSVersionInfoSize := sizeof(TOSversionInfo);
+  GetVersionEx(wv);
+
+  Result := (wv.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS);
+
+  if(wv.dwPlatformId = VER_PLATFORM_WIN32_NT) then
+    begin
+      TokenHandle := 0;
+      if OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, TokenHandle) then
+        try
+          ReturnLength := 0;
+          GetTokenInformation(TokenHandle, TokenGroups, nil, 0, ReturnLength);
+          TokenInformation := GetMemory(ReturnLength);
+          if Assigned(TokenInformation) then
+            try
+              if GetTokenInformation(TokenHandle, TokenGroups,
+                TokenInformation, ReturnLength, ReturnLength) then
+              begin
+                AdminSid := GetAdminSid;
+                for Loop := 0 to TokenInformation^.GroupCount - 1 do
+                  begin
+                    if EqualSid(TokenInformation^.Groups[Loop].Sid, AdminSid) then
+                      begin
+                        Result := True; break;
+                      end;
+                  end;
+                FreeSid(AdminSid);
+              end;
+            finally
+              FreeMemory(TokenInformation);
+            end;
+        finally
+          CloseHandle(TokenHandle);
+        end;
+    end;
+end;
+
+function WVersion: string; 
+var 
+  OSInfo: TOSVersionInfo; 
+begin 
+  Result := '3X'; 
+  OSInfo.dwOSVersionInfoSize := sizeof(TOSVERSIONINFO); 
+  GetVersionEx(OSInfo); 
+  case OSInfo.dwPlatformID of 
+    VER_PLATFORM_WIN32S: begin 
+        Result := '3X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_WINDOWS: begin 
+        Result := '9X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_NT: begin 
+        Result := 'NT'; 
+        Exit; 
+      end; 
+  end; //case 
+end;
Index: /oup/releases/0.29a3/src/TFileTypeRegistration/SysUtils.inc
===================================================================
--- /oup/releases/0.29a3/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
+++ /oup/releases/0.29a3/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
@@ -0,0 +1,307 @@
+function fileexists(const szFilename: string): boolean;
+var
+  Handle   : THandle;
+  FindData : TWin32FindData;
+begin
+  Handle := FindFirstFile(pchar(szFilename),FindData);
+  Result := (Handle <> INVALID_HANDLE_VALUE);
+
+  if(Result) then Windows.FindClose(Handle);
+end;
+
+function ExtractFileDrive(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') then
+    begin
+      Result := copy(szFilename,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFilePath(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFileName);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') or
+      (szFileName[i] = '\') then
+    begin
+      Result := copy(szFileName,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFileName(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '\') then
+      break;
+
+    dec(i);
+  end;
+
+  Result := copy(szFilename,i + 1,length(szFilename));
+end;
+
+function CutFileExt(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '.') then
+      break;
+
+    dec(i);
+  end;
+
+  if(i = 0) then Result := szFilename
+    else Result := copy(szFilename,1,i-1);
+end;
+
+function ChangeFileExt(const szFileName, szNewExt: string): string;
+begin
+  Result := CutFileExt(szFileName);
+
+  if(szNewExt[1] <> '.') then Result := Result + '.' + szNewExt
+    else Result := Result + szNewExt;
+end;
+
+function FileSearch(const Name, DirList: string): string;
+var
+  I, P, L: Integer;
+begin
+  Result := Name;
+  P      := 1;
+  L      := length(DirList);
+
+  while(true) do begin
+    if(fileexists(Result)) then exit;
+
+    while(P <= L) and (DirList[P] = ';') do inc(P);
+    if(P > L) then break;
+
+    I := P;
+    while(P <= L) and (DirList[P] <> ';') do inc(P);
+
+    Result   := copy(DirList,I,P-I);
+    if not(Result[length(Result)] in[':','\']) then
+      Result := Result + '\';
+
+    Result := Result + Name;
+  end;
+
+  Result  := '';
+end;
+
+function StrToIntDef(const s: string; const i: integer): integer;
+var
+  code : integer;
+begin
+  Val(s,Result,code); if(code <> 0) then
+                        Result := i;
+end;
+
+function IntToStr(const i: integer): string;
+begin
+  Str(i,Result);
+end;
+
+// -----------------------------------------------------------------------------
+
+function Format(fmt: string; params: array of const): string;
+var
+  pdw1,
+  pdw2 : PDWORD;
+  i    : integer;
+  pc   : PCHAR;
+begin
+  pdw1 := nil;
+
+  if High(params) >= 0 then
+    GetMem(pdw1, (High(params) + 1) * sizeof(Pointer));
+
+  pdw2  := pdw1;
+  for i := 0 to High(params) do
+    begin
+      pdw2^ := PDWORD(@params[i])^;
+      inc(pdw2);
+    end;
+
+  pc := GetMemory(1024);
+  if Assigned(pc) then
+    try
+      SetString(Result, pc, wvsprintf(pc, PCHAR(fmt), PCHAR(pdw1)));
+    finally
+      if (pdw1 <> nil) then FreeMem(pdw1);
+      FreeMem(pc);
+    end
+  else
+    Result := '';
+end;
+
+
+// -----------------------------------------------------------------------------
+
+function UpperCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        Result[i] := UpCase(s[i]);
+    end;
+end;
+
+function LowerCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        case s[i] of
+          'A'..'Z','Ä','Ö','Ü':
+            Result[i] := CHR(BYTE(s[i]) + 32);
+          else
+            Result[i] := s[i];
+        end;
+    end;
+end;
+
+function LoggedUser: string;
+var
+  dwLen  : dword;
+  fTest  : boolean;
+begin
+  Result := '';
+  dwLen  := MAX_PATH; SetLength(Result,dwLen);
+
+  fTest  := GetUserName(@Result[1],dwLen);
+
+  if(not fTest) and (GetLastError = ERROR_MORE_DATA) then begin
+    SetLength(Result,dwLen);
+    fTest := GetUserName(@Result[1],dwLen);
+  end;
+
+  if(fTest) and (Result[1] <> #0) then
+    SetLength(Result,dwLen - 1);
+end;
+
+// -----------------------------------------------------------------------------
+
+//
+// delete files during next reboot (code by sakura)
+//
+function DeleteFileDuringNextSystemBoot(aFileName: string): Boolean;
+var
+  ShortName,
+  winini    : string;
+  os        : TOSVersionInfo;
+  ts        : array of string;
+  f         : TextFile;
+  i         : integer;
+begin
+  Result := False;
+
+  // get OS version
+  os.dwOSVersionInfoSize := sizeof(TOSVersionInfo);
+  GetVersionEx(os);
+
+  case os.dwPlatformId of
+    // NT systems
+    VER_PLATFORM_WIN32_NT:
+      Result := MoveFileEx(pchar(aFileName),nil,
+        MOVEFILE_REPLACE_EXISTING + MOVEFILE_DELAY_UNTIL_REBOOT);
+    // 9x systems
+    VER_PLATFORM_WIN32_WINDOWS:
+      begin
+        // get Windows folder
+        SetLength(winini,MAX_PATH+1);
+        SetLength(winini,GetWindowsDirectory(@winini[1],MAX_PATH+1));
+
+        if(winini <> '') then begin
+          if(winini[length(winini)] <> '\') then
+            winini := winini + '\';
+          winini   := winini + 'wininit.ini';
+
+          // get short name of the given file
+          SetLength(ShortName,MAX_PATH+1);
+          SetLength(ShortName,
+            GetShortPathName(@aFilename[1],@ShortName[1],MAX_PATH+1));
+
+          if(ShortName <> '') then begin
+            // add it to "wininit.ini" to delete
+            // during next reboot
+            SetLength(ts,0);
+
+            {$I-}
+            // get old file´s content
+            AssignFile(f,winini);
+            ReSet(f);
+            if(IoResult = 0) then begin
+              while(not eof(f)) do begin
+                SetLength(ts,length(ts)+1);
+                ReadLn(f,ts[length(ts)-1]);
+
+                if(lstrcmpi('[rename]',pchar(ts[length(ts)-1])) = 0) then begin
+                  SetLength(ts,length(ts)+1);
+                  ts[length(ts)-1] := 'NUL='+ShortName;
+                end;
+              end;
+              CloseFile(f);
+            end;
+
+            if(length(ts) = 0) then begin
+              SetLength(ts,2);
+              ts[0] := '[rename]';
+              ts[1] := 'NUL='+ShortName;
+            end;
+
+            // re-create
+            ReWrite(f);
+            Result := (IoResult = 0);
+            if(Result) then begin
+              for i := 0 to length(ts) - 1 do
+                WriteLn(f,ts[i]);
+
+              CloseFile(f);
+            end;
+            {$I+}
+
+            SetLength(ts,0);
+          end;
+        end;
+      end;
+    // only 9x and NT are supported
+    else
+      exit;
+  end;
+end;
Index: /oup/releases/0.29a3/src/TFileTypeRegistration/demo.txt
===================================================================
--- /oup/releases/0.29a3/src/TFileTypeRegistration/demo.txt	(revision 8)
+++ /oup/releases/0.29a3/src/TFileTypeRegistration/demo.txt	(revision 8)
@@ -0,0 +1,34 @@
+uses
+  ftypesAPI;
+
+var
+  ftr    : TFileTypeRegistration;
+  s:String;
+
+
+ftr := TFileTypeRegistration.Create;
+if(ftr <> nil) then begin
+  try
+    if(LOWORD(wp) = IDC_CREATEFOO) then begin
+      if(ftr.RegisterType('.foo','FooFile','FOO-File')) then begin
+        ftr.AddHandler('open','notepad.exe "%1"','Öffnen');
+        ftr.AddHandler('print','notepad.exe /p "%1"');
+        ftr.SetDefaultHandler;
+        ftr.AddNewFileSupport('.foo');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_DELPRINTVERB) then begin
+      if(ftr.GetInternalKey('.foo') <> '') then begin
+        ftr.DeleteHandler('print');
+        ftr.SetDefaultHandler('open');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_REMOVEFOO) then begin
+      s := ftr.GetInternalKey('.foo');
+      if(MessageBox(hwndDlg,pchar('Wollen Sie wirklich ".foo" und "' + s + '" entfernen?'), 'Frage',MB_YESNO or MB_DEFBUTTON2 or MB_ICONQUESTION) = ID_YES) then
+        ftr.UnregisterType('.foo');
+    end;
+  finally
+    ftr.Free;
+  end;
+end;
Index: /oup/releases/0.29a3/src/TFileTypeRegistration/ftypesAPI.pas
===================================================================
--- /oup/releases/0.29a3/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
+++ /oup/releases/0.29a3/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
@@ -0,0 +1,544 @@
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse (Win32-API)
+// Copyright (c) 2004 Mathias Simmack
+//
+// -----------------------------------------------------------------------------
+
+// -- Revision history ---------------------------------------------------------
+//
+//   * erste Version
+//
+// -----------------------------------------------------------------------------
+unit ftypesAPI;
+
+interface
+
+uses
+  Windows, ShlObj;
+
+type
+  TFileTypeRegistration = class
+    FRegConnector : HKEY;
+    FExtension,
+    FInternalName : string;
+    FVerb         : string;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function RegisterType(const Extension, InternalName: string;
+      Description: string = ''; IconFile: string = '';
+      IconIndex: integer = -1): boolean;
+    function UnregisterExtension(const Extension: string): boolean;
+    function UnregisterType(const Extension: string): boolean;
+    procedure UpdateShell;
+    function AddHandler(const HandlerVerb, CommandLine: string;
+      HandlerDescription: string = ''): boolean; overload;
+    function DeleteHandler(const HandlerVerb: string): boolean;
+    function SetDefaultHandler: boolean; overload;
+    function SetDefaultHandler(const HandlerVerb: string): boolean; overload;
+    function GetInternalKey(const Extension: string): string;
+    function AddNewFileSupport(const Extension: string): boolean;
+    function RemoveNewFileSupport(const Extension: string): boolean;
+
+    property Extension: string read FExtension;
+    property InternalName: string read FInternalName;
+    property CurrentVerb: string read FVerb;
+  end;
+
+
+implementation
+
+(* *****************************************************************************
+
+  Beispiel #1: Einen neuen Dateityp registrieren
+  ----------------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // die Dateiendung ".foo" registrieren, der interne Schlüssel
+    // lautet "FooFile", eine Beschreibung und eine Symboldatei
+    // sind ebenfalls angegeben
+    if(ftr.RegisterType('.foo','FooFile','FOO Description',
+      'c:\folder\icon.ico')) then
+    begin
+      // fügt den Handler "open" hinzu und verknüpft ihn mit dem
+      // Programm "foo.exe"
+      ftr.AddHandler('open','"c:\folder\foo.exe" "%1"');
+
+      // setzt den zuletzt benutzten Handler ("open" in dem Fall)
+      // als Standard
+      ftr.SetDefaultHandler;
+    end;
+
+    if(ftr.RegisterType('.foo','ThisIsNotTheFOOKey')) then
+    // Das ist kein Fehler! Obwohl hier der interne Name
+    // "ThisIsNotTheFOOKey" verwendet wird, benutzt die Funktion
+    // intern den bereits vorhandenen Schlüssel "FooFile" (s. oben).
+    begin
+      // zwei neue Handler werden registriert, ...
+      ftr.AddHandler('print','"c:\folder\foo.exe" /p "%1"');
+      ftr.AddHandler('edit','notepad.exe "%1"');
+
+      // ... & dank der überladenen Funktion "SetDefaultHandler"
+      // kann diesmal auch "print" als Standardhandler gesetzt
+      // werden
+      ftr.SetDefaultHandler('print');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #2: Einen neuen Typ mit einem vorhandenen Schlüssel
+  verknüpfen
+  ------------------------------------------------------------
+
+  Das Beispiel registriert die Endung ".foo" auf die gleiche
+  Weise wie Textdateien (.txt). Es wird einfach der interne
+  Schlüsselname ermittelt und für die Endung ".foo" gesetzt
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    strInternalTextFileKey := ftr.GetInternalKey('.txt');
+    if(strInternalTextFileKey <> '') then
+      ftr.RegisterType('.foo',strInternalTextFileKey);
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #3: Einen Handler entfernen
+  ------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // den internen Schlüsselnamen des Typs ".foo" ermitteln, ...
+    if(ftr.GetInternalKey('.foo') <> '') then
+    // ... wobei das Ergebnis in dem Fall unwichtig ist, weil
+    // intern auch die Eigenschaft "FInternalName" gesetzt
+    // wird
+    begin
+      // den "print"-Handler entfernen, ...
+      ftr.DeleteHandler('print');
+
+      // ... & den Standardhandler aktualisieren
+      ftr.SetDefaultHandler('open');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #4: Nur eine Dateiendung entfernen
+  -------------------------------------------
+
+  In diesem Fall wird lediglich die Endung ".foo" entfernt. Der
+  evtl. vorhandene interne Schlüssel bleibt bestehen. Das ist
+  für das Beispiel #2 nützlich, wenn die Endung ".foo" entfernt
+  werden soll, intern aber mit den Textdateien verlinkt ist, die
+  ja im Normalfall nicht entfernt werden dürfen/sollten.
+
+    ftr.UnregisterExtension('.foo');
+
+
+  Beispiel #5: Den kompletten Dateityp entfernen
+  ----------------------------------------------
+
+  Dieses Beispiel entfernt dagegen den kompletten Dateityp,
+  inkl. des evtl. vorhandenen internen Schlüssels (vgl. mit
+  Beispiel #4).
+
+    ftr.UnregisterType('.foo');
+
+  Bezogen auf Beispiel #2 wäre das die fatale Lösung, weil dadurch
+  zwar die Endung ".foo" deregistriert wird, gleichzeitig wird
+  aber auch der intern verwendete Schlüssel der Textdateien
+  gelöscht.
+
+  ALSO, VORSICHT!!!
+
+***************************************************************************** *)
+
+
+//
+// Admin-Rechte sind erforderlich (Funktion von NicoDE)
+//
+{$INCLUDE IsAdmin.inc}
+{$INCLUDE SysUtils.inc}
+
+
+// -----------------------------------------------------------------------------
+//
+// Registry
+//
+// -----------------------------------------------------------------------------
+
+function RegWriteSubKeyVal(const parent: HKEY; SubKeyName: string;
+  ValueName, Value: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := false;
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegCreateKeyEx(parent,pchar(SubKeyName),0,nil,0,KEY_READ or KEY_WRITE,
+    nil,tmp,nil) = ERROR_SUCCESS) then
+  try
+    Result := (RegSetValueEx(tmp,pchar(ValueName),0,REG_SZ,pchar(Value),
+      length(Value) + 1) = ERROR_SUCCESS);
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegReadSubKeyStr(const parent: HKEY; SubKeyName: string;
+  ValueName: string): string;
+var
+  tmp     : HKEY;
+  lpData,
+  dwLen   : dword;
+begin
+  Result  := '';
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegOpenKeyEx(parent,pchar(SubKeyName),0,KEY_READ,
+    tmp) = ERROR_SUCCESS) then
+  try
+    lpData := REG_NONE;
+    dwLen  := 0;
+    if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,nil,
+         @dwLen) = ERROR_SUCCESS) and
+      (lpData in[REG_SZ,REG_EXPAND_SZ]) and
+      (dwLen > 0) then
+    begin
+      SetLength(Result,dwLen);
+
+      if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,
+           @Result[1],@dwLen) = ERROR_SUCCESS) then
+        SetLength(Result,dwLen - 1)
+      else
+        Result := '';
+    end;
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegKeyExists(const parent: HKEY; KeyName: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := (RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,tmp) =
+    ERROR_SUCCESS);
+  if(Result) then RegCloseKey(tmp);
+end;
+
+function RegDeleteWholeKey(parent: HKEY; KeyName: string): boolean;
+var
+  reg       : HKEY;
+  dwSubkeys : dword;
+  dwLen     : dword;
+  i         : integer;
+  buf       : array[0..MAX_PATH]of char;
+begin
+  if(RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,reg) = ERROR_SUCCESS) then
+  try
+    if(RegQueryInfoKey(reg,nil,nil,nil,@dwSubKeys,nil,
+      nil,nil,nil,nil,nil,nil) = ERROR_SUCCESS) and
+      (dwSubKeys > 0) then
+    for i := 0 to dwSubKeys - 1 do begin
+      ZeroMemory(@buf,sizeof(buf));
+      dwLen   := MAX_PATH;
+
+      if(RegEnumKeyEx(reg,i,buf,dwLen,nil,nil,nil,nil) = ERROR_SUCCESS) and
+        (dwLen > 0) then
+      RegDeleteWholeKey(reg,buf);
+    end;
+  finally
+    RegCloseKey(reg);
+  end;
+
+  Result := (RegDeleteKey(parent,pchar(KeyName)) = ERROR_SUCCESS);
+end;
+
+
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse
+//
+// -----------------------------------------------------------------------------
+
+constructor TFileTypeRegistration.Create;
+var
+  key: HKEY;
+  sub: PChar;
+begin
+  FExtension    := '';
+  FInternalName := '';
+  FVerb         := '';
+
+  // Zugriff auf die Registry, & HKEY_CLASSES_ROOT
+  // als Root setzen
+  if(WVersion='9X') or IsAdmin then begin
+    key:=HKEY_CLASSES_ROOT;
+    sub:=nil;
+  end else begin
+    key:=HKEY_CURRENT_USER;
+    sub:=PChar('SOFTWARE\Classes');
+  end;
+
+  if RegOpenKeyEx(key,sub,0,KEY_ALL_ACCESS, FRegConnector) <> ERROR_SUCCESS then
+    FRegConnector := INVALID_HANDLE_VALUE;
+end;
+
+destructor TFileTypeRegistration.Destroy;
+begin
+  if(FRegConnector <> INVALID_HANDLE_VALUE) then
+    RegCloseKey(FRegConnector);
+end;
+
+function TFileTypeRegistration.RegisterType(const Extension,
+  InternalName: string; Description: string = ''; IconFile: string = '';
+  IconIndex: integer = -1): boolean;
+var
+  strDummy : string;
+begin
+  // Standardergebnis
+  Result         := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // ist dieser Typ evtl. schon registriert?
+  strDummy := self.GetInternalKey(Extension);
+
+  // Nein. :o)
+  if(strDummy = '') then strDummy := InternalName;
+
+  // den Schlüssel mit der Dateiendung anlegen oder aktualisieren
+  Result := RegWriteSubKeyVal(FRegConnector,Extension,'',strDummy);
+  if(not Result) then exit;
+
+  // den internen Schlüssel öffnen
+  if(Result) then
+  begin
+    // Beschreibung anlegen
+    if(Description <> '') then
+      RegWriteSubKeyVal(FRegConnector,strDummy,'',Description);
+
+    // Symbol zuweisen (Datei muss existieren!)
+    if(IconFile <> '') and
+      (fileexists(IconFile)) then
+    begin
+      if(IconIndex <> -1) then
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',Format('%s,%d',[IconFile,IconIndex]))
+      else
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',IconFile);
+    end;
+  end;
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+
+  // Properties aktualisieren
+  if(Result) then
+  begin
+    FExtension    := Extension;
+    FInternalName := strDummy;
+  end;
+end;
+
+function TFileTypeRegistration.UnregisterExtension(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // die Endung entfernen
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegDeleteWholeKey(FRegConnector,Extension));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+function TFileTypeRegistration.UnregisterType(const Extension: string):
+  boolean;
+var
+  strDummy : string;
+begin
+  Result   := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // den internen Namen der Endung ermitteln
+  strDummy := self.GetInternalKey(Extension);
+
+  // die Endung entfernen (s. "UnregisterExtension"), ...
+  Result   := (self.UnregisterExtension(Extension)) and
+  // ... & den internen Schlüssel löschen
+    (strDummy <> '') and
+    (RegKeyExists(FRegConnector,strDummy)) and
+    (RegDeleteWholeKey(FRegConnector,strDummy));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+procedure TFileTypeRegistration.UpdateShell;
+begin
+  SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,nil,nil);
+end;
+
+
+const
+  ShellKey = '%s\shell\%s';
+
+function TFileTypeRegistration.AddHandler(const HandlerVerb,
+  CommandLine: string; HandlerDescription: string = ''): boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') or
+    (CommandLine = '') then exit;
+
+  // der interne Schlüssel muss existieren
+  if(RegKeyExists(FRegConnector,FInternalName)) then
+  begin
+    // den Handler (= Verb) erzeugen
+    Result := RegWriteSubKeyVal(FRegConnector,
+      Format(ShellKey + '\command',[FInternalName,HandlerVerb]),
+      '',
+      CommandLine);
+
+    // ggf. Beschreibung für Handler setzen
+    if(HandlerDescription <> '') then
+      RegWriteSubKeyVal(FRegConnector,
+        Format(ShellKey,[FInternalName,HandlerVerb]),
+        '',
+        HandlerDescription);
+  end;
+
+  // interne Eigenschaft anpassen (für "SetDefaultHandler")
+  if(Result) then
+    FVerb := HandlerVerb;
+end;
+
+function TFileTypeRegistration.DeleteHandler(const HandlerVerb: string):
+  boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // Handlerschlüssel entfernen (sofern vorhanden)
+  Result :=
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) and
+    (RegDeleteWholeKey(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb])));
+end;
+
+function TFileTypeRegistration.SetDefaultHandler: boolean;
+begin
+  if(FInternalName <> '') and (FVerb <> '') then
+    Result := self.SetDefaultHandler(FVerb)
+  else
+    Result := false;
+end;
+
+function TFileTypeRegistration.SetDefaultHandler(const HandlerVerb: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // interner Schlüssel muss existieren, ...
+  if(RegKeyExists(FRegConnector,FInternalName)) and
+  // ... & Handler muss existieren, ...
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) then
+  begin
+  // ... dann den Handler als Standard eintragen
+    Result := RegWriteSubKeyVal(FRegConnector,FInternalName + '\shell',
+      '',HandlerVerb);
+  end;
+end;
+
+function TFileTypeRegistration.GetInternalKey(const Extension: string): string;
+begin
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // einen evtl. eingestellten internen Namen zurücksetzen
+  FInternalName   := '';
+
+  // den Schlüssel der Dateiendung öffnen, ...
+  if(RegKeyExists(FRegConnector,Extension)) then
+    FInternalName := RegReadSubKeyStr(FRegConnector,Extension,'');
+
+  // ... als Funktionsergebnis zurückliefern
+  if(not RegKeyExists(FRegConnector,FInternalName)) then
+    FInternalName := '';
+
+  Result := FInternalName;
+end;
+
+
+function TFileTypeRegistration.AddNewFileSupport(const Extension: string):
+  boolean;
+var
+  Description : string;
+begin
+  Result      := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // interne Beschreibung des Typs ermitteln
+  if(self.GetInternalKey(Extension) <> '') then
+    Description := RegReadSubKeyStr(FRegConnector,FInternalName,'')
+  else
+    Description := '';
+
+  // die Beschreibung darf keine Leerzeichen enthalten, weil sie
+  // als Referenz für den neuen Dateinamen verwendet wird, ...
+  if(pos(#32,Description) > 0) or
+  // ... & sie darf auch nicht leer sein
+    (Description = '') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegWriteSubKeyVal(FRegConnector,Extension + '\ShellNew','NullFile',''));
+end;
+
+function TFileTypeRegistration.RemoveNewFileSupport(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension + '\ShellNew')) and
+    (RegDeleteWholeKey(FRegConnector,Extension + '\ShellNew'));
+end;
+
+end.
Index: /oup/releases/0.29a3/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.29a3/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,952 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit9_data_structures;
+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;
+  raw_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.CreateLevel(source,target:String);
+  VAR
+    i:LongWord;
+  BEGIN
+  END;
+
+PROCEDURE TForm10.CreateDatabase(source,target:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+  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:=target;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=loaded_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:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    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;
+
+        rawlist:=GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              mem:=TMemoryStream.Create;
+              filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+              filestream.Seek(rawlist[j].raw_addr,soFromBeginning);
+              mem.CopyFrom(filestream,rawlist[j].raw_size);
+              filestream.Free;
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") );';
+              Query.ExecSQL;
+              mem.Free;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        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 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 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 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 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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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',False,NIL);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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.29a3/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+object Form11: TForm11
+  Left = 0
+  Top = 0
+  Caption = 'Extractor'
+  ClientHeight = 398
+  ClientWidth = 487
+  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
+      MultiSelect = True
+      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.29a3/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit11_extractor.pas	(revision 8)
@@ -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(GetFilesCount)+')');
+    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(GetFileIDByName(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+            END ELSE BEGIN
+              ExportFile(GetFileIDByName(list.Items.Strings[list.ItemIndex]),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(GetFileIDByName(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+          END ELSE BEGIN
+            ExportFile(GetFileIDByName(list.Items.Strings[list.ItemIndex]),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.29a3/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.29a3/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,119 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      13..16: BEGIN
+              Exit;
+              edit_new.EditType:=etInteger;
+              edit_new.LimitCheck:=True;
+              edit_new.Max:=Int((Power(256,datatype-13)) / 2)-1;
+              edit_new.Min:=1-Int((Power(256,datatype-13)) / 2)-1;
+            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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.29a3/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,324 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  ClientHeight = 640
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = []
+      OnKeyUp = hexKeyUp
+      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 = 600
+      Width = 483
+      Height = 40
+      Align = alBottom
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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 = 374
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 337
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 352
+        Width = 146
+        Height = 88
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        OnResize = panel_extensionResize
+        object lbl_filter: TLabel
+          Left = 2
+          Top = 46
+          Width = 100
+          Height = 17
+          AutoSize = False
+          Caption = 'Filter by &extension:'
+          FocusControl = combo_extension
+        end
+        object combo_extension: TComboBox
+          Left = 2
+          Top = 60
+          Width = 145
+          Height = 21
+          Style = csDropDownList
+          DropDownCount = 12
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Tahoma'
+          Font.Style = []
+          ItemHeight = 0
+          ParentFont = False
+          Sorted = True
+          TabOrder = 2
+          OnClick = combo_extensionClick
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.29a3/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,809 @@
+UNIT Unit13_rawedit;
+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, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+  dat_offset:LongWord;
+  fileid_opened,dat_offset_opened:LongWord;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    IF list_offset.Count=0 THEN BEGIN
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF GetFileIDByName(list.Items.Strings[i])=raw_info.src_id THEN BEGIN
+          list.ItemIndex:=i;
+          listClick(Self);
+          Break;
+        END;
+      END;
+      FOR i:=0 TO list_offset.Count-1 DO BEGIN
+        IF MidStr(list_offset.Items.Strings[i],3,8)=IntToHex(raw_info.src_offset,8) THEN BEGIN
+          list_offset.ItemIndex:=i;
+          Break;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    LoadRawFilebyIDOffset(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+    count:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=GetExtensionsList;
+    FOR i:=0 TO High(RawListHandlers) DO BEGIN
+      count:=Length(GetFilesList(RawListHandlers[i].Ext,'',True));
+      combo_extension.Items.Add(RawListHandlers[i].ext+' ('+IntToStr(count)+')');
+    END;
+//    FOR i:=0 TO High(exts) DO
+//      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm13.LoadFileNames;
+  VAR
+    Extension:String;
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringList;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN BEGIN
+      Extension:='';
+      FOR i:=0 TO High(RawListHandlers) DO BEGIN
+        IF Length(Extension)>0 THEN Extension:=Extension+',';
+        Extension:=Extension+RawListHandlers[i].Ext;
+      END;
+    END;
+
+    files:=GetFilesList(extension,pattern,TRUE);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    list_offset.Enabled:=True;
+    IF GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,8)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,8));
+    LoadRaw(GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of 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;
+          UpdateRawFile(GetRawInfo(fileid_opened,dat_offset_opened),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+{      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+}    END;
+  END;
+
+PROCEDURE TForm13.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  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
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+*)    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.29a3/src/Unit14_settings.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit14_settings.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit14_settings.dfm	(revision 8)
@@ -0,0 +1,75 @@
+object Form14: TForm14
+  Left = 0
+  Top = 0
+  BorderStyle = bsToolWindow
+  Caption = 'Settings'
+  ClientHeight = 350
+  ClientWidth = 250
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object check_filesashex: TCheckBox
+    Left = 8
+    Top = 8
+    Width = 145
+    Height = 17
+    Caption = 'Show filenumbers as Hex'
+    TabOrder = 0
+  end
+  object btn_ok: TButton
+    Left = 8
+    Top = 319
+    Width = 57
+    Height = 23
+    Caption = 'OK'
+    Default = True
+    TabOrder = 1
+    OnClick = btn_okClick
+  end
+  object btn_cancel: TButton
+    Left = 120
+    Top = 319
+    Width = 57
+    Height = 23
+    Cancel = True
+    Caption = 'Cancel'
+    TabOrder = 2
+    OnClick = btn_cancelClick
+  end
+  object btn_register_oldb: TButton
+    Left = 8
+    Top = 128
+    Width = 169
+    Height = 25
+    Caption = 'Register .oldb files with OUP'
+    TabOrder = 3
+    OnClick = btn_register_oldbClick
+  end
+  object btn_register_opf: TButton
+    Left = 8
+    Top = 159
+    Width = 169
+    Height = 25
+    Caption = 'Register .opf files with OUP'
+    TabOrder = 4
+    OnClick = btn_register_opfClick
+  end
+  object btn_register_dat: TButton
+    Left = 8
+    Top = 97
+    Width = 169
+    Height = 25
+    Caption = 'Register .dat files with OUP'
+    TabOrder = 5
+    OnClick = btn_register_datClick
+  end
+end
Index: /oup/releases/0.29a3/src/Unit14_settings.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit14_settings.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit14_settings.pas	(revision 8)
@@ -0,0 +1,155 @@
+unit Unit14_settings;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils;
+
+type
+  TForm14 = class(TForm)
+    check_filesashex: TCheckBox;
+    btn_ok: TButton;
+    btn_cancel: TButton;
+    btn_register_oldb: TButton;
+    btn_register_opf: TButton;
+    btn_register_dat: TButton;
+    procedure btn_register_opfClick(Sender: TObject);
+    procedure btn_register_oldbClick(Sender: TObject);
+    procedure btn_register_datClick(Sender: TObject);
+    procedure btn_cancelClick(Sender: TObject);
+    procedure btn_okClick(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormShow(Sender: TObject);
+    function RegisterExtension(ext:String):Integer;
+  private
+  public
+  end;
+
+var
+  Form14: TForm14;
+
+implementation
+{$R *.dfm}
+uses
+  Unit1_main, Unit3_data, ftypesAPI;
+
+function ExtensionRegistered(ext:String; var RegisteredAs:String):Boolean;
+  var
+    ftr:TFileTypeRegistration;
+  begin
+    ftr:=TFileTypeRegistration.Create;
+    if(ftr <> nil) then begin
+      try
+        RegisteredAs:=ftr.GetInternalKey(ext);
+        if RegisteredAs<>'' then
+          Result:=True
+        else
+          Result:=False;
+      finally
+        ftr.Free;
+      end;
+    end;
+  end;
+
+function TForm14.RegisterExtension(ext:String):Integer;
+  var
+    ftr:TFileTypeRegistration;
+    temps:String;
+    warnmsg:String;
+  begin
+    Result:=-1;
+    if ExtensionRegistered(ext,temps) then begin
+      if temps<>'ONI'+ext then begin
+        warnmsg:=ext+'-files are not registered to OUP but as "'+temps+'"-files.'+#13+#10+
+                 'Do you really want to unregister'+ext+'-files?';
+        if MessageBox(Self.Handle, PChar(warnmsg),PChar('Warning'),MB_YESNO)=ID_NO then
+          Exit;
+      end;
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then
+        try
+          if not ftr.UnregisterExtension(ext) then
+            ShowMessage('Could not unregister '+ext+'-files')
+          else
+            Result:=2;
+        finally
+          ftr.Free;
+        end;
+    end else begin
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then begin
+        try
+          if ftr.RegisterType(ext,'ONI'+ext,'ONI '+ext+'-file',Application.EXEname+',1') then begin
+            ftr.AddHandler('open','"'+Application.EXEname+'" '+MidStr(ext,2,Length(ext)-1)+' "%1"');
+            ftr.SetDefaultHandler;
+            Result:=1;
+          end;
+        finally
+          ftr.Free;
+        end;
+      end;
+    end;
+  end;
+
+procedure TForm14.btn_cancelClick(Sender: TObject);
+  begin
+    Self.Close;
+  end;
+
+procedure TForm14.btn_okClick(Sender: TObject);
+  begin
+    AppSettings.FilenumbersAsHex:=check_filesashex.Checked;
+    Self.Close;
+  end;
+
+procedure TForm14.btn_register_datClick(Sender: TObject);
+  begin
+    case RegisterExtension('.dat') of
+      2: btn_register_dat.Caption:='Register .dat files with OUP';
+      1: btn_register_dat.Caption:='Unregister .dat files';
+    end;
+  end;
+
+procedure TForm14.btn_register_oldbClick(Sender: TObject);
+  begin
+    case RegisterExtension('.oldb') of
+      2: btn_register_oldb.Caption:='Register .oldb files with OUP';
+      1: btn_register_oldb.Caption:='Unregister .oldb files';
+    end;
+  end;
+
+procedure TForm14.btn_register_opfClick(Sender: TObject);
+  begin
+    case RegisterExtension('.opf') of
+      2: btn_register_opf.Caption:='Register .opf files with OUP';
+      1: btn_register_opf.Caption:='Unregister .opf files';
+    end;
+  end;
+
+procedure TForm14.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  begin
+    CanClose:=False;
+    Self.Visible:=False;
+    Form1.Enabled:=True;
+    Form1.SetFocus;
+  end;
+
+procedure TForm14.FormShow(Sender: TObject);
+  var
+    temps:String;
+  begin
+    if ExtensionRegistered('.dat',temps) then
+      btn_register_dat.Caption:='Unregister .dat files'
+    else
+      btn_register_dat.Caption:='Register .dat files with OUP';
+    if ExtensionRegistered('.oldb',temps) then
+      btn_register_oldb.Caption:='Unregister .oldb files'
+    else
+      btn_register_oldb.Caption:='Register .oldb files with OUP';
+    if ExtensionRegistered('.opf',temps) then
+      btn_register_opf.Caption:='Unregister .opf files'
+    else
+      btn_register_opf.Caption:='Register .opf files with OUP';
+    check_filesashex.Checked:=AppSettings.FilenumbersAsHex;
+  end;
+
+end.
Index: /oup/releases/0.29a3/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  Caption = 'Form1'
+  ClientHeight = 525
+  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 = 508
+    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
+    ExplicitTop = 489
+  end
+  object tabs: TTabSet
+    Left = 0
+    Top = 488
+    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
+    ExplicitTop = 469
+  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 ClosefileDB1: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = ClosefileDB1Click
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_settings: TMenuItem
+        Caption = 'Se&ttings...'
+        OnClick = menu_settingsClick
+      end
+      object menu_sep4: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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
+    object menu_About: TMenuItem
+      Caption = '&About'
+      OnClick = menu_AboutClick
+    end
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 520
+  end
+end
Index: /oup/releases/0.29a3/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,526 @@
+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, Unit9_data_structures,
+  Unit10_leveldb, Unit4_exporters, Unit14_settings,
+  Unit5_preview, Unit7_txmpreplace, Unit8_binedit, Unit11_extractor, Unit13_rawedit;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    ClosefileDB1: TMenuItem;
+    menu_sep4: TMenuItem;
+    menu_settings: TMenuItem;
+    menu_About: TMenuItem;
+    procedure menu_AboutClick(Sender: TObject);
+    PROCEDURE menu_settingsClick(Sender: TObject);
+    PROCEDURE ClosefileDB1Click(Sender: TObject);
+    PROCEDURE menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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;
+
+    IF MidStr(ParamStr(1),1,3)='opf' THEN BEGIN
+      ShowMessage('Load OPF-File: '+ParamStr(2));
+    END ELSE IF MidStr(ParamStr(1),1,4)='oldb' THEN BEGIN
+      OpenDatabase(ParamStr(2));
+      IF opened_state=opened_db THEN BEGIN
+        menu_tools.Enabled:=True;
+        menu_convert.Enabled:=False;
+        statbar.Panels.Items[0].Text:='OLDB loaded: '+ParamStr(2);
+        statbar.Panels.Items[1].Text:='Files: '+IntToStr(GetFilesCount);
+        statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(GetExtensionsList));
+      END ELSE BEGIN
+        menu_tools.Enabled:=False;
+        menu_convert.Enabled:=True;
+      END;
+    END ELSE IF MidStr(ParamStr(1),1,3)='dat' THEN BEGIN
+      IF LoadDatInfos(ParamStr(2)) THEN BEGIN
+        Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(ParamStr(2))+')';
+        statbar.Panels.Items[0].Text:='.dat loaded: '+ParamStr(2);
+        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:=False;
+      END ELSE BEGIN
+        menu_convert.Enabled:=True;
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an Oni-.dat-file?');
+      END;
+    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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+        END ELSE BEGIN
+          menu_convert.Enabled:=True;
+          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 Length(tablist)=0 THEN BEGIN
+        IF opened_state=opened_db THEN CloseDatabase;
+        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:=False;
+          statbar.Panels.Items[0].Text:='OLDB loaded: '+opend.FileName;
+          statbar.Panels.Items[1].Text:='Files: '+IntToStr(GetFilesCount);
+          statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(GetExtensionsList));
+        END ELSE BEGIN
+          menu_tools.Enabled:=False;
+          menu_convert.Enabled:=True;
+        END;
+      END;
+    END;
+  END;
+PROCEDURE TForm1.ClosefileDB1Click(Sender: TObject);
+  BEGIN
+    menu_windows_closeallClick(Form1);
+    IF Length(tablist)=0 THEN BEGIN
+      IF opened_state=opened_db THEN CloseDatabase;
+      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: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+PROCEDURE TForm1.menu_settingsClick(Sender: TObject);
+  BEGIN
+    Form14.Visible:=True;
+    Self.Enabled:=False;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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.menu_AboutClick(Sender: TObject);
+  begin
+    ShowMessage('Will be implemented later ;)');
+  end;
+
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.29a3/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,683 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data, 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 GetFilesCount:LongWord;
+FUNCTION GetExtensionsList:TStringList;
+FUNCTION GetFileIDByName(name:String):LongWord;
+
+FUNCTION HexToLong(hex:String):LongWord;
+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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+FUNCTION LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; 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;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringList;
+
+
+IMPLEMENTATION
+USES Unit4_Exporters, Unit9_data_structures;
+
+VAR
+  Database:TABSDatabase;
+  Query:TABSQuery;
+
+TYPE
+  TValueSwitcher=Record
+    CASE IsFloat: Boolean OF
+      True: (ValueFloat:Single);
+      False: (ValueInt:LongWord);
+  END;
+
+
+FUNCTION HexToLong(hex:String):LongWord;
+  FUNCTION NormalizeHexString(VAR hex:String):Boolean;
+    VAR
+      i:Byte;
+    BEGIN
+      IF hex[1]='$' THEN BEGIN
+        FOR i:=1 TO Length(hex)-1 DO BEGIN
+          hex[i]:=hex[i+1];
+        END;
+        SetLength(hex, Length(hex)-1);
+      END;
+      IF (hex[1]='0') AND (UpCase(hex[2])='X') THEN BEGIN
+        FOR i:=1 TO Length(hex)-2 DO BEGIN
+          hex[i]:=hex[i+2];
+        END;
+        SetLength(hex, Length(hex)-2);
+      END;
+      IF Length(hex)=0 THEN
+        Result:=False
+      ELSE
+        Result:=True;
+    END;
+  VAR
+    i:Byte;
+  BEGIN
+    IF NormalizeHexString(hex) THEN BEGIN
+      hex:=UpperCase(hex);
+      Result:=0;
+      FOR i:=1 TO Length(hex) DO BEGIN
+        Result:=Result SHL 4;
+        CASE hex[i] OF
+          '0'..'9': Result:=Result+Ord(hex[i])-48;
+          'A'..'F': Result:=Result+Ord(hex[i])-55;
+        ELSE
+          Result:=0;
+          Exit;
+        END;
+      END;
+    END ELSE BEGIN
+      Result:=0;
+    END;
+  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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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:=Query.FieldByName('size').AsInteger;
+        Result.FileType:=Query.FieldByName('contenttype').AsInteger;
+        Result.DatAddr:=0;
+        Result.opened:=False;
+      END;
+      Query.Close;
+    END;
+  END;
+
+FUNCTION GetFileIDByName(name:String):LongWord;
+  BEGIN
+    IF AppSettings.FilenumbersAsHex THEN
+      Result:=HexToLong(MidStr(name,1,4))
+    ELSE
+      Result:=StrToInt(MidStr(name,1,5));
+  END;
+
+FUNCTION GetFilesCount:LongWord;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=dat_header.Files;
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT Count(*) AS cnumber FROM datfiles;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        Result:=Query.FieldByName('cnumber').AsInteger;
+      END ELSE Result:=0;
+      Query.Close;
+    END;
+  END;
+
+FUNCTION GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringList;
+  VAR
+    i:LongWord;
+    where:String;
+    where_ext: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 (Pos(dat_files[i].Extension,ext)>0) ) 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);
+              IF AppSettings.FilenumbersAsHex THEN
+                Result[High(Result)]:=dat_files[i].FileNameHex
+              ELSE
+                Result[High(Result)]:=dat_files[i].FileName;
+            END;
+          END ELSE BEGIN
+            SetLength(Result,Length(Result)+1);
+            IF AppSettings.FilenumbersAsHex THEN
+              Result[High(Result)]:=dat_files[i].FileNameHex
+            ELSE
+              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 ';
+        IF Pos(',',ext)>0 THEN BEGIN
+          i:=1;
+          where_ext:='';
+          WHILE i<Length(ext) DO BEGIN
+            IF Length(where_ext)>0 THEN where_ext:=where_ext+' OR ';
+            where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")';
+            i:=i+5;
+          END;
+          where:=where+'('+where_ext+')';
+        END ELSE BEGIN
+          where:=where+'(extension="'+ext+'")';
+        END;
+      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;
+    header_pc,header_mac:Boolean;
+  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));
+    header_pc:=True;
+    header_mac:=True;
+    FOR i:=0 TO High(dat_header.Ident) DO BEGIN
+      IF dat_header.Ident[i]<>header_ident1_pc[i] THEN BEGIN
+        header_pc:=False;
+      END;
+      IF dat_header.Ident[i]<>header_ident1_mac[i] THEN BEGIN
+        header_mac:=False;
+      END;
+    END;
+    IF NOT (header_pc OR header_mac) THEN BEGIN
+      Result:=False;
+      Exit;
+    END ELSE BEGIN
+      IF (header_pc AND NOT header_mac) THEN
+        dat_os_mac:=False
+      ELSE
+        IF (NOT header_pc AND header_mac) THEN
+          dat_os_mac:=True
+        ELSE BEGIN
+          Result:=False;
+          Exit;
+        END;
+    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;
+      dat_files[i].FileNameHex:=IntToHex(i,4)+'-'+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,dat_offset,raw_addr,size:LongWord; loc_sep:Boolean; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenRead)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),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)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      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 LoadRawFileByIDOffset(fileid,dat_offset:LongWord; target:Pointer):Boolean;
+  VAR
+    i:Byte;
+    raw_info:TRawInfo;
+    mem:TStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      raw_info:=GetRawInfo(fileid,dat_offset);
+      LoadRawFile(fileid,dat_offset,raw_info.raw_addr,raw_info.raw_size,raw_info.loc_sep,target);
+    END ELSE BEGIN
+      Query.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Result:=True;
+        mem:=Query.CreateBlobStream(Query.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      END;
+      Query.Close;
+    END;
+  END;
+FUNCTION UpdateRawFile(rawinfo:TRawInfo; target:Pointer):Boolean;
+  VAR
+    filestream:TFileStream;
+  BEGIN
+    Result:=False;
+    IF opened_state=opened_dat THEN BEGIN
+      Result:=True;
+      IF NOT rawinfo.loc_sep THEN
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.raw'),fmOpenReadWrite)
+      ELSE
+        filestream:=TFileStream.Create(AnsiReplaceStr(dat_filename,'.dat','.sep'),fmOpenReadWrite);
+      filestream.Seek(rawinfo.raw_addr,soFromBeginning);
+      filestream.Write(target^,rawinfo.raw_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;
+    rawlist:TRawList;
+  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
+        rawlist:=GetRawList(fileid);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR i:=0 TO High(rawlist) DO BEGIN
+            ExportRawFile(fileid,rawlist[i].src_offset,path+'\'+GetWinFileName(filename));
+          END;
+        END;
+      END;
+    END;
+  END;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringList;
+  VAR
+    start,len:Word;
+  BEGIN
+    SetLength(Result, 0);
+    start:=1;
+    WHILE PosEx(delimiter,_string,start)>0 DO BEGIN
+      len:=PosEx(delimiter,_string,start)-start;
+      SetLength(Result, Length(Result)+1);
+      Result[High(Result)]:=MidStr(_string,start,len);
+      start:=start+len+1;
+    END;
+    SetLength(Result, Length(Result)+1);
+    Result[High(Result)]:=MidStr(_string,start,Length(_string)-start+1);
+  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.29a3/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,116 @@
+UNIT Unit3_data;
+INTERFACE
+USES Classes;
+
+CONST
+  version:String='v0.29a';
+  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;
+    FileNameHex: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];
+    FilenumbersAsHex:Boolean;
+  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;
+
+  TRawInfo=RECORD
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+    loc_sep:Boolean;
+  END;
+  TRawList=Array OF TRawInfo;
+
+VAR
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_os_mac:Boolean=False;
+  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_pc: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_ident1_mac:Array[0..$13] OF Byte=
+      ($61,$30,$C1,$23,$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.29a3/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,218 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, Dialogs, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset: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, Unit9_data_structures;
+
+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;
+
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    SetLength(data, GetRawInfo(fileid, dat_offset).raw_size);
+    LoadRawFileByIDOffset(fileid,dat_offset,@data[0]);
+    IF FileExists(filename+'.raw0x'+IntToHex(dat_offset,8)) THEN BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd);
+    END ELSE BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),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,$44,rawpos,Length(data),False,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.29a3/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Caption = 'Preview'
+  ClientHeight = 473
+  ClientWidth = 472
+  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.29a3/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit5_preview.pas	(revision 8)
@@ -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(GetFilesCount)+')');
+    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:=GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    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.29a3/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,409 @@
+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; VAR faded:Tdata):Boolean;
+
+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*(imgdepth DIV 8))+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;
+  VAR
+    img_addr:LongWord;
+  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);
+    IF NOT dat_os_mac THEN
+      LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr)
+    ELSE
+      LoadDatFilePart(fileid,$A0,SizeOf(img_addr),@img_addr);
+
+    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);
+
+    IF NOT dat_os_mac THEN
+      LoadRawFile(fileid,$9C,img_addr,Result.datasize,dat_os_mac,@Result.imgdata[0])
+    ELSE
+      LoadRawFile(fileid,$A0,img_addr,Result.datasize,dat_os_mac,@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; VAR faded:Tdata):Boolean;
+  VAR
+    i:LongWord;
+    x,y:Word;
+    imgdata:Tdata;
+    fadelvldata:Tdata;
+  BEGIN
+    Result:=False;
+    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,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) OR ((x MOD 2)=1) OR ((y MOD 2)=1);
+    IF (x>1) AND (y>1) THEN Exit;
+    Result:=True;
+    SetLength(faded, Length(imgdata));
+    FOR i:=0 TO Length(imgdata)-1 DO faded[i]:=imgdata[i];
+  END;
+
+END.
Index: /oup/releases/0.29a3/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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 = 'MIP Mapping'
+      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.29a3/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,231 @@
+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:=GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+
+    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:=GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+      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;
+
+      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_fading.Checked THEN
+        IF Not CreateFadedImage(imgpkg,imgpkg.imgdata) THEN
+          IF MessageBox(Self.Handle, PChar('Can not create a MipMapped-image (probably because of a wrong dimension).'+#13+#10+'Do you want to continue without MipMapping?'), PChar('Warning'), MB_YESNO)=ID_YES THEN
+            check_fading.Checked:=False
+          ELSE
+            Exit;
+
+      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);
+
+      rawfile:=TFileStream.Create(raw_filename,fmOpenReadWrite);
+
+      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);
+
+      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(GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]));
+      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.29a3/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.29a3/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.29a3/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,385 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 555
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 555
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+    ExplicitHeight = 423
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 555
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    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 = 450
+      Width = 483
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitTop = 375
+    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 = []
+      OnKeyUp = hexKeyUp
+      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 value_viewer: TWrapGrid
+      Left = 0
+      Top = 218
+      Width = 483
+      Height = 232
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      PopupMenu = value_viewer_context
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+    object VST: TVirtualStringTree
+      Left = 0
+      Top = 458
+      Width = 483
+      Height = 97
+      Align = alBottom
+      AnimationDuration = 0
+      AutoExpandDelay = 300
+      BiDiMode = bdLeftToRight
+      Colors.UnfocusedSelectionColor = clGradientActiveCaption
+      Colors.UnfocusedSelectionBorderColor = clGradientActiveCaption
+      Ctl3D = True
+      DragOperations = []
+      DrawSelectionMode = smBlendedRectangle
+      EditDelay = 200
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      Header.AutoSizeIndex = 0
+      Header.Font.Charset = DEFAULT_CHARSET
+      Header.Font.Color = clWindowText
+      Header.Font.Height = -11
+      Header.Font.Name = 'Tahoma'
+      Header.Font.Style = []
+      Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoVisible]
+      Header.PopupMenu = VTHPopup
+      Header.Style = hsFlatButtons
+      HintAnimation = hatNone
+      HintMode = hmTooltip
+      Indent = 14
+      ParentBiDiMode = False
+      ParentCtl3D = False
+      ParentFont = False
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 2
+      TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning]
+      TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowRoot, toShowTreeLines, toShowVertGridLines, toUseBlendedImages]
+      TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect]
+      OnDblClick = VSTDblClick
+      OnFocusChanged = VSTFocusChanged
+      OnGetText = VSTGetText
+      OnHeaderDragged = VSTHeaderDragged
+      Columns = <
+        item
+          MaxWidth = 300
+          MinWidth = 100
+          Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 0
+          Spacing = 20
+          Width = 150
+          WideText = 'Name'
+          WideHint = 'Name of the item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 1
+          Spacing = 20
+          Width = 85
+          WideText = 'Offset'
+          WideHint = 'Offset of the data-item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 75
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 2
+          Width = 75
+          WideText = 'Type'
+          WideHint = 'Data type of the item.'
+        end
+        item
+          MaxWidth = 250
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 3
+          Width = 100
+          WideText = 'Value'
+          WideHint = 'Value of the item.'
+        end
+        item
+          MaxWidth = 400
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 4
+          Width = 400
+          WideText = 'Description'
+        end>
+      WideDefaultText = ''
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 555
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Bevel1: TBevel
+      Left = 0
+      Top = 491
+      Width = 150
+      Height = 6
+      Align = alBottom
+      Style = bsRaised
+      ExplicitTop = 359
+    end
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 388
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 388
+      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 = 497
+      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
+  object VTHPopup: TVTHeaderPopupMenu
+    OnColumnChange = VTHPopupColumnChange
+    Left = 200
+    Top = 496
+  end
+end
Index: /oup/releases/0.29a3/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,879 @@
+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, Math,
+  VirtualTrees, VTHeaderPopup;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    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;
+    VST: TVirtualStringTree;
+    VTHPopup: TVTHeaderPopupMenu;
+    procedure VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex);
+    procedure VSTDblClick(Sender: TObject);
+    procedure VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+      const Column: TColumnIndex; Visible: Boolean);
+    procedure VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+      OldPosition: Integer);
+    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE LoadDat(_fileid:LongWord);
+    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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    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 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, Unit13_rawedit;
+VAR
+  fileid:LongWord;
+
+TYPE
+  PNodeData = ^TNodeData;
+  TNodeData = record
+    Caption:String;
+    Offset:LongInt;
+    DataType:Word;
+    Value:String;
+    Description:String;
+  end;
+
+
+function AddVSTEntry(AVST:TCustomVirtualStringTree; ANode:PVirtualNode; ARecord:TNodeData):PVirtualNode;
+  var
+    data:PNodeData;
+  begin
+    Result:=AVST.AddChild(ANode);
+    data:=AVST.GetNodeData(Result);
+    AVST.ValidateNode(Result,False);
+    data^:=ARecord;
+  end;
+
+
+
+PROCEDURE TForm8.LoadDat(_fileid:LongWord);
+  VAR
+    i:LongWord;
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF GetFileIDByName(list.Items.Strings[i])=fileid THEN BEGIN
+            list.ItemIndex:=i;
+            Exit;
+          END;
+        END;
+      END;
+    END;
+    fileid:=_fileid;
+    FOR i:=0 TO list.Count-1 DO
+      IF GetFileIDByName(list.Items.Strings[i])=fileid THEN
+        list.ItemIndex:=i;
+    Self.ClearStructViewer;
+    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; 
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringList;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(GetFilesCount)+')');
+    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
+    LoadDat(GetFileIDByName(list.Items.Strings[list.ItemIndex]));
+  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]);
+      11: Result:='0x'+IntToHex(GetRawInfo(fileid,offset).raw_addr,8);
+      12: Result:=FormatNumber(hex.data[offset+1]+hex.data[offset+2]*256+hex.data[offset+3]*256*256,5,'0');
+      13: Result:=IntToStr(hex.data[offset]);
+      14: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256);
+      15: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256);
+      16: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256);
+      1000..9999: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-1000 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Result:=Result+'.';
+          END;
+        END;
+      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;
+  VAR
+    i,j:LongWord;
+    pdata: PNodeData;
+    data: TNodeData;
+    node: PVirtualNode;
+    structs: TStructDef;
+  BEGIN
+    VST.BeginUpdate;
+    IF VST.RootNodeCount=0 THEN BEGIN
+      structs:=LoadStructureDefinition(fileid);
+      IF structs.data THEN BEGIN
+        IF Length(structs.Global)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Global) DO BEGIN
+            data.Caption:=structs.Global[i].name;
+            data.Offset:=structs.Global[i].offset;
+            data.DataType:=structs.Global[i].datatype;
+            data.Value:=GetValue(structs.Global[i].datatype, structs.Global[i].offset);
+            data.Description:=structs.Global[i].description;
+            AddVSTEntry(VST, nil, data);
+          END;
+        END;
+        IF Length(structs.Subs)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Subs) DO BEGIN
+            WITH structs.Subs[i] DO BEGIN
+              IF Length(Entries)>0 THEN BEGIN
+                IF Pos('#',SubName)>0 THEN BEGIN
+                  data.Offset:=HexToLong(MidStr(SubName, Pos('#',SubName)+1, 8));
+                  data.Value:=MidStr(SubName, PosEx('#',SubName,Pos('#',SubName)+1)+1, 8);
+                  data.Caption:=MidStr(SubName, 1, Pos('#',SubName)-1);
+                  data.Description:=SubDesc;
+                END ELSE BEGIN
+                  data.Caption:=SubName;
+                  data.Description:=SubDesc;
+                  data.Offset:=0;
+                  data.Value:='';
+                END;
+                data.DataType:=0;
+                node:=AddVSTEntry(VST, nil, data);
+                data.Description:='';
+                FOR j:=0 TO High(Entries) DO BEGIN
+                  data.Caption:=Entries[j].name;
+                  data.Offset:=Entries[j].offset;
+                  data.DataType:=Entries[j].datatype;
+                  data.Value:=GetValue(Entries[j].datatype, Entries[j].offset);
+                  data.Description:=Entries[j].description;
+                  AddVSTEntry(VST, node, data);
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      IF VST.RootNodeCount>0 THEN
+        VST.FocusedNode:=VST.GetFirst;
+    END ELSE BEGIN
+      Node:=VST.GetFirst;
+      WHILE Assigned(Node) DO BEGIN
+        pdata:=VST.GetNodeData(Node);
+        IF pdata.DataType>0 THEN
+          pdata.Value:=GetValue(pdata.Datatype, pdata.Offset);
+        Node:=VST.GetNext(Node);
+      END;
+    END;
+    VST.EndUpdate;
+  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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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;
+    VST.NodeDataSize:=SizeOf(TNodeData);
+    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;
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  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);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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;
+  BEGIN
+    VST.Clear;
+  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.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos;
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm8.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm8.hexSelectionChanged(Sender: TObject);
+  VAR
+    selstart:Integer;
+    i,j:Word;
+
+    node:PVirtualNode;
+    pdata:PNodeData;
+  BEGIN
+    IF hex.DataSize>0 THEN BEGIN
+      WriteValues;
+      selstart:=hex.SelStart;
+      IF VST.RootNodeCount>0 THEN BEGIN
+        Node:=VST.GetFirst;
+        WHILE Assigned(Node) DO BEGIN
+          pdata:=VST.GetNodeData(Node);
+          IF pdata.DataType>0 THEN BEGIN
+            IF ((selstart-pdata.Offset)<GetTypeDataLength(pdata.DataType)) AND ((selstart-pdata.Offset)>=0) THEN BEGIN
+              VST.FocusedNode:=Node;
+              VST.Selected[Node]:=True;
+              Break;
+            END;
+          END;
+          Node:=VST.GetNext(Node);
+        END;
+      END;
+    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.VSTDblClick(Sender: TObject);
+  var
+    node:PVirtualNode;
+    nodedata:PNodeData;
+  begin
+    if VST.FocusedColumn=3 then begin
+      node:=VST.FocusedNode;
+      nodedata:=VST.GetNodeData(node);
+
+      IF NOT (nodedata.datatype IN [11,12]) THEN BEGIN
+        Form12.MakeVarInput(nodedata.Caption,nodedata.offset,nodedata.datatype,nodedata.value,Self);
+      END ELSE BEGIN
+        IF nodedata.DataType=11 THEN BEGIN
+          IF GetRawInfo(fileid,nodedata.offset).raw_size>0 THEN BEGIN
+            IF Form1.open_child('rawedit') THEN BEGIN
+              TForm13(Form1.ActiveMDIChild).LoadRaw(GetRawInfo(fileid,nodedata.offset));
+            END;
+          END;
+        END;
+        IF nodedata.DataType=12 THEN BEGIN
+          IF (StrToInt(nodedata.Value)<GetFilesCount) AND
+              (StrToInt(nodedata.Value)>0) AND
+              (StrToInt(nodedata.Value)<>fileid) THEN BEGIN
+            IF GetFileInfo(StrToInt(nodedata.Value)).Size>0 THEN BEGIN
+              IF Form1.open_child('binedit') THEN BEGIN
+                TForm8(Form1.ActiveMDIChild).LoadDat(StrToInt(nodedata.Value));
+              END;
+            END ELSE BEGIN
+              ShowMessage('Linked filed is a zero-byte-file');
+            END;
+          END;
+        END;
+      END;
+
+    end;
+  end;
+
+procedure TForm8.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex);
+  var
+    data:PNodeData;
+  begin
+    data:=VST.GetNodeData(node);
+    IF data.DataType>0 THEN BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+GetTypeDataLength(data.DataType)-1;
+    END ELSE BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+HexToLong(data.Value)-1;
+    END;
+  end;
+
+procedure TForm8.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+  var
+    data:PNodeData;
+  begin
+    data := Sender.GetNodeData(Node);
+    CellText := '';
+    if TextType = ttNormal then begin
+      case Column of
+        0: CellText := data.Caption;
+        1:
+          if data.DataType>0 then
+            CellText := '0x'+IntToHex(data.Offset,8)
+          else
+            if data.Offset>0 then
+              CellText := '0x'+IntToHex(data.Offset,8);
+        2:
+          if data.DataType>0 then
+            CellText := GetDataType(data.DataType);
+        3:
+          if data.DataType>0 then
+            CellText := GetValue(data.DataType, data.Offset)
+          else
+            if Length(data.Value)>0 then
+              CellText := IntToStr(HexToLong(data.Value))+' Bytes';
+        4:
+          CellText := data.Description;
+      end;
+    end;
+  end;
+
+procedure TForm8.VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+  OldPosition: Integer);
+  begin
+    if Sender.Columns.Items[column].Position<1 then
+      Sender.Columns.Items[column].Position:=OldPosition;
+  end;
+
+procedure TForm8.VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+  const Column: TColumnIndex; Visible: Boolean);
+  begin
+    if column=0 then
+      TVirtualStringTree(Sender).Header.Columns.Items[column].Options:=TVirtualStringTree(Sender).Header.Columns.Items[column].Options+[coVisible];
+  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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+
+END.
Index: /oup/releases/0.29a3/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.29a3/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.29a3/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,511 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, ABSMain, DB, ABSDecUtil, Classes, Unit3_data, Dialogs, StrUtils;
+
+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
+                      // 11    : raw-addr
+                      // 12    : dat-file-ID
+                      // 13..16: Signed Integer[1..4]
+                      // 1000..9999: Unused data[0-8999]
+                      // 10000+: string[0+]
+      description:String;
+    END;
+  TStructDefSub=RECORD
+      SubName:String;
+      SubDesc:String;
+      Entries:Array OF TStructure_entry;
+    END;
+  TStructDef=RECORD
+      Data:Boolean;
+      Global:Array OF TStructure_entry;
+      Subs:Array OF TStructDefSub;
+    END;
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+
+VAR
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+
+
+IMPLEMENTATION
+USES Unit2_functions, Forms;
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      12: Result:=4;
+      13..16: Result:=datatype-12;
+      1000..9999: Result:=datatype-1000;
+      10000..65535: Result:=datatype-10000;
+    END;
+  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';
+      11: Result:='Raw-Address';
+      12: Result:='.dat-file-ID';
+      13..16: Result:='SignedInt'+IntToStr((typeid-12)*8);
+      1000..9999: Result:='Unused('+IntToStr(typeid-1000)+')';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+FUNCTION GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  VAR
+    i:LongWord;
+    raw_list:TRawList;
+  BEGIN
+    raw_list:=GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    FOR i:=0 TO High(raw_list) DO BEGIN
+      IF raw_list[i].src_offset=dat_offset THEN BEGIN
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Result.loc_sep:=raw_list[i].loc_sep;
+        Break;
+      END;
+    END;
+  END;
+
+FUNCTION GetRawList(fileid:LongWord):TRawList;
+  VAR
+    i:LongWord;
+    Query:TABSQuery;
+  BEGIN
+    IF opened_state=opened_dat THEN BEGIN
+      FOR i:=0 TO High(RawListHandlers) DO
+        IF UpperCase(RawListHandlers[i].Ext)=UpperCase(dat_files[fileid].extension) THEN
+          IF RawListHandlers[i].needed THEN BEGIN
+            Result:=RawListHandlers[i].Handler(fileid);
+            Break;
+          END ELSE
+            Break;
+    END ELSE BEGIN
+      SetLength(Result,0);
+      Query.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+      Query.Open;
+      IF Query.RecordCount>0 THEN BEGIN
+        Query.First;
+        SetLength(Result,Query.RecordCount);
+        i:=0;
+        REPEAT
+          Result[i].src_id:=fileid;
+          Result[i].src_offset:=Query.FieldByName('src_link_offset').AsInteger;
+          Result[i].raw_addr:=0;
+          Result[i].raw_size:=Query.FieldByName('size').AsInteger;
+          Inc(i);
+          Query.Next;
+        UNTIL Query.EOF;
+      END;
+      Query.Close;
+    END;
+  END;
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*4;
+        LoadDatFilePart(fileid,$20+i*4,4,@link);
+        Result[i].raw_addr:=link;
+        Result[i].raw_size:=0{????????????????????????????????};
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION AKVA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$1C,4,@links);
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*$74+$24;
+        LoadDatFilePart(fileid,$20+i*$74+$24,4,@link);
+        Result[i].raw_addr:=link;
+        LoadDatFilePart(fileid,$20+i*$74+$28,4,@link);
+        Result[i].raw_size:=link;
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$0C,4,@link);
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$08,4,@datasize);
+    LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      LoadDatFilePart(fileid,$40,4,@datasize);
+      LoadDatFilePart(fileid,$44,4,@link);
+      Result[0].src_offset:=$44;
+    END ELSE BEGIN
+      LoadDatFilePart(fileid,$10,4,@datasize);
+      LoadDatFilePart(fileid,$14,4,@link);
+      Result[0].src_offset:=$14;
+    END;
+    SetLength(Result,1);
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=False;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,link:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    LoadDatFilePart(fileid,$18,4,@baselink);
+    LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      LoadDatFilePart(fileid,$20+(links-1)*4,4,@link);
+      SetLength(data,link+1024);
+      LoadRawFile(fileid,$1C,baselink,link+1024,False,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[link+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=link+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    LoadDatFilePart(fileid,$182,1,@tempb);
+    LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    LoadDatFilePart(fileid,$183,1,@tempb);
+    LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    LoadDatFilePart(fileid,$184,1,@tempb);
+    LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    LoadDatFilePart(fileid,$185,1,@tempb);
+    LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    LoadDatFilePart(fileid,$186,1,@tempb);
+    LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    LoadDatFilePart(fileid,$187,1,@tempb);
+    LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    LoadDatFilePart(fileid,$154,2,@tempw);
+    LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    LoadDatFilePart(fileid,$138,4,@templ);
+    LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link_pc:LongWord;
+    link_mac:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    LoadDatFilePart(fileid,$9C,4,@link_pc);
+    LoadDatFilePart(fileid,$A0,4,@link_mac);
+    CASE storetype OF
+      0,1,2: datasize:=x*y*2;
+      8: datasize:=x*y*4;
+      9: datasize:=x*y DIV 2;
+    END;
+    SetLength(Result,1);
+    IF NOT dat_os_mac THEN BEGIN
+      Result[0].src_offset:=$9C;
+      Result[0].raw_addr:=link_pc
+    END ELSE BEGIN
+      Result[0].src_offset:=$A0;
+      Result[0].raw_addr:=link_mac;
+    END;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+  VAR
+    i:LongWord;
+    current_type:Byte; //0: Global, 1: Undynamic, 2: Dynamic
+    current_base,current_package,current_package_size:LongWord;
+    packages:LongWord;
+    deffile:Text;
+    structentry:TStructure_Entry;
+    fields:TStringList;
+    filename:String;
+    ext:String[4];
+    temps:String;
+    data:TData;
+  BEGIN
+    SetLength(Result.Global,0);
+    SetLength(Result.Subs,0);
+    Result.Data:=False;
+    ext:=GetFileInfo(fileid).Extension;
+    filename:=ExtractFilePath(Application.ExeName)+'\StructDefs\'+ext+'.txt';
+    IF FileExists(filename) THEN BEGIN
+      data:=LoadDatFile(fileid);
+      AssignFile(deffile,filename);
+      Reset(deffile);
+      current_type:=0;
+      Result.Data:=True;
+      IF NOT EoF(deffile) THEN BEGIN
+        ReadLn(deffile,temps);
+        WHILE NOT EoF(deffile) DO BEGIN
+          ReadLn(deffile,temps);
+          IF (Length(temps)>0) AND (temps[1]<>'#') THEN BEGIN
+            IF temps[1]='*' THEN BEGIN
+              fields:=Explode(temps,#9);
+              CASE Length(fields) OF
+                1..2: BEGIN
+                     current_type:=1;
+                     current_base:=0;
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                     IF Length(fields)=2 THEN
+                       Result.Subs[High(Result.Subs)].SubDesc:=fields[1];
+                   END;
+                3: BEGIN
+                     current_type:=1;
+                     current_base:=HexToLong(fields[2]);
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                     Result.Subs[High(Result.Subs)].SubDesc:=fields[1];
+                   END;
+                6: BEGIN
+                     current_type:=2;
+                     current_base:=HexToLong(fields[2]);
+                     current_package:=0;
+                     current_package_size:=StrToInt(fields[5]);
+                     IF fields[4][1]<>'$' THEN BEGIN
+                       CASE StrToInt(fields[4]) OF
+                         1: packages:=data[HexToLong(fields[3])];
+                         2: packages:=data[HexToLong(fields[3])]+data[HexToLong(fields[3])+1]*256;
+                         4: packages:=data[HexToLong(fields[3])]+data[HexToLong(fields[3])+1]*256+data[HexToLong(fields[3])+2]*256*256+data[HexToLong(fields[3])+3]*256*256*256;
+                       END;
+                     END ELSE BEGIN
+                       packages:=HexToLong(fields[4]);
+                     END;
+                     SetLength(Result.Subs, Length(Result.Subs)+packages);
+                     FOR current_package:=0 TO packages-1 DO BEGIN
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubName:=
+                           MidStr(fields[0],2,Length(fields[0])-1)+'['+IntToStr(current_package)+']'+
+                           '#'+IntToHex(current_base+current_package*current_package_size,8)+
+                           '#'+IntToHex(current_package_size,8);
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubDesc:=
+                           fields[1];
+                     END;
+                   END;
+              END;
+            END ELSE BEGIN
+              fields:=Explode(temps,#9);
+              IF (Length(fields)=3) OR (Length(fields)=4) THEN BEGIN
+                structentry.name:=fields[0];
+                structentry.datatype:=StrToInt(fields[2]);
+                IF Length(fields)=4 THEN
+                  structentry.description:=fields[3]
+                ELSE
+                  structentry.description:='';
+                IF current_type IN [0,1] THEN BEGIN
+                  structentry.offset:=HexToLong(fields[1])+current_base;
+                  IF Length(Result.Subs)=0 THEN BEGIN
+                    SetLength(Result.Global,Length(Result.Global)+1);
+                    Result.Global[High(Result.Global)]:=structentry;
+                  END ELSE BEGIN
+                    SetLength(Result.Subs[High(Result.Subs)].Entries,Length(Result.Subs[High(Result.Subs)].Entries)+1);
+                    Result.Subs[High(Result.Subs)].Entries[High(Result.Subs[High(Result.Subs)].Entries)]:=structentry;
+                  END;
+                END ELSE BEGIN
+                  FOR current_package:=0 TO packages-1 DO BEGIN
+                    structentry.offset:=current_base+current_package*current_package_size+HexToLong(fields[1]);
+                    WITH Result.Subs[High(Result.Subs)-packages+current_package+1] DO BEGIN
+                      SetLength(Entries,Length(Entries)+1);
+                      Entries[High(Entries)]:=structentry;
+                    END;
+                  END;
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      CloseFile(deffile);
+    END;
+  END;
+
+
+BEGIN
+//  InsertRawListHandler('AGDB',True,AGDB);
+  InsertRawListHandler('AKVA',True,AKVA);
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.29a3/todo.txt
===================================================================
--- /oup/releases/0.29a3/todo.txt	(revision 8)
+++ /oup/releases/0.29a3/todo.txt	(revision 8)
@@ -0,0 +1,156 @@
+Unit10 unabhängig, funktionsweise wiederherstellen
+Schreibt auch die dat_files[] etc
+Benutzt die *globalen* dat_stream/raw_stream und keine MemCopy
+
+-Datei von einem Tool in andrem Tool öffnen
+
+-TXMPReplace: Zugriff über Unit2
+
+
+-SELECT [src_id],MIN(datfiles.[name]),SUM(rawmap.[size]) FROM rawmap INNER  JOIN datfiles ON datfiles.[id]=[src_id] GROUP BY [src_id] ORDER BY [src_id] ASC
+
+-Extrahier-Ordner-Option (mit Platzhalter für .dat-Name)
+
+-HELP.hlp
+-About
+
+-BinEdit: Zusatzfunktionen wie: Suche, 
+-BinEdit: Bild/Menu/Button irgendwas zum speichern
+
+-Extractor: Wohin?
+
+-FileCompare: Ergebnis=Tabelle, jede Zeile eine differenz-addresse, spalten = werte an addr. für compared files
+
+-TXMP-Replace: MultiReplace
+
+-Move-Freischalter (Mindestlvl eingabe)
+
+-Löschen einer Datei auf die gelinkt wird: Liste der Links und sicherheitsfrage
+
+-Filebox-Context: Extract etc
+
+-DAT geladen -> Meldung oder sogar "what to do next?"
+-SSG: Levels extrahieren?
+-Pierre: Wie Char-Anims, Char-Models, Levels extrahieren?
+-Language-Files?
+-STRG+C auf Dateilisten etc für kopieren des Namens
+
+-REPACKING: testen lvl0: 690-collisions.txmp einbauen, script: collisions-zeug
+
+#################################################################
+##########                 File-Types                  ##########
+#################################################################
+(3CLA)
+ABNA
+AGDB
+AGQC
+AGQG
+(AGQM)
+AGQR
+AISA
+AITR
+(AIWA)
+AKAA
+AKBA
+AKBP
+AKDA
+AKEV
+AKOT
+AKVA
+BINA
+CBPI
+CBPM
+CONS
+CRSA
+DOOR
+DPge
+(EDIA)
+ENVP
+FILM
+(FXLR)
+(GMAN)
+HPge
+IDXA
+IGHH
+IGPA
+IGPG
+IGSA
+IGSt
+Impt
+IPge
+KeyI
+M3GA
+M3GM
+(M3TA)
+Mtrl
+(NMSA)
+OBAN
+OBDC
+(OBLS)
+OBOA
+OFGA
+ONCC
+ONCP
+ONCV
+ONFA
+ONGS
+ONIA
+ONLD
+ONLV
+ONMA
+ONOA
+ONSA
+ONSK
+ONTA
+ONVL
+ONWC
+OPge
+OSBD
+OTIT
+OTLF
+PLEA
+PNTA
+PSpc
+PSpL
+PSUI
+QTNA
+(QUDA)
+SNDD
+StNA
+SUBT
+(TMFA)
+(TMRA)
+TRAC
+TRAM
+TRAS
+TRBS
+TRCM
+(TRFT)
+TRGA
+TRGE
+TRIA
+TRIG
+TRMA
+TRSC
+TRTA
+TSFF
+TSFL
+TSFT
+TSGA
+TStr
+TURR
+TXAN
+TXCA
+TXMA
+TXMB
+TXMP
+(TXPC)
+TxtC
+(UUEA)
+(UVDL)
+VCRA
+WMCL
+WMDD
+WMM_
+WMMB
+WPge
Index: /oup/releases/0.30a/StructDefs/AISA.txt
===================================================================
--- /oup/releases/0.30a/StructDefs/AISA.txt	(revision 8)
+++ /oup/releases/0.30a/StructDefs/AISA.txt	(revision 8)
@@ -0,0 +1,10 @@
+AI Character Setup Array
+
+File ID	$00	12
+Level ID	$04	4
+Unused	$08	1022
+Packages	$1E	2
+
+*AIs		$20	$1E	2	352
+ONCC-Linkk	$28	12
+Intro func	$50	10032
Index: /oup/releases/0.30a/StructDefs/ONCC.txt
===================================================================
--- /oup/releases/0.30a/StructDefs/ONCC.txt	(revision 8)
+++ /oup/releases/0.30a/StructDefs/ONCC.txt	(revision 8)
@@ -0,0 +1,58 @@
+Oni character class
+TXMP link	$28	12	Shadow texture
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use an hypo
+Hurt light sound	$98	10032	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	10032	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	10032	Reference to an OSBD file of level 0
+Death sound	$F8	10032	Reference to an OSBD file of level 0
+Taunt sound query	$2B0	10	00 = not used; 64 = used
+"Whos there?" sound query	$2B1	10	00 = not used; 64 = used
+"I see you" sound query	$2B2	10	00 = not used; 64 = used
+"You lose" sound query	$2B3	10	00 = not used; 64 = used
+"Where are you?" sound query	$2B4	10	00 = not used; 64 = used
+"Why is this happenung?" sound query	$2B5	10	00 = not used; 64 = used
+Superpunch sound query	$2B6	10	00 = not used; 64 = used
+Superkick sound query	$2B7	10	00 = not used; 64 = used
+Super3 sound query	$2B8	10	00 = not used; 64 = used
+Super4 sound query	$2B9	10	00 = not used; 64 = used
+Taunt sound	$2BC	10032	Reference to a SNDD file of level 0
+"Whos there?" sound	$2DC	10032	Reference to a SNDD file of level 0
+"I see you" sound	$2FC	10032	Reference to a SNDD file of level 0
+"You lose" sound	$31C	10032	Reference to a SNDD file of level 0
+"Where are you?" sound	$33C	10032	Reference to a SNDD file of level 0
+"Why is this happenung?" sound	$35C	10032	Reference to a SNDD file of level 0
+Superpunch sound	$37C	10032	Reference to a SNDD file of level 0
+Superkick sound	$39C	10032	Reference to a SNDD file of level 0
+Super3 sound	$3BC	10032	Reference to a SNDD file of level 0
+Super4 sound	$3DC	10032	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV link	$434	12	Character varient link
+ONCP link	$438	12	Character particle array link; useless?
+ONIA link	$43C	12	Character impact array link; useless?
+Unknown	$444	10016	Maybe the weight of the character?
+Footstep walk impact	$454	10128	Reference to the a Impt file of level 0
+Footstep run impact	$4D6	10128	Reference to the a Impt file of level 0
+Footstep crouch impact	$558	10128	Reference to the a Impt file of level 0
+Fall slide impact	$5DA	10128	Reference to the a Impt file of level 0
+Fall land impact	$65C	10128	Reference to the a Impt file of level 0
+Fall land hard impact	$6DE	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$760	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$7E2	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$864	10128	Reference to the a Impt file of level 0
+Footstep turn impact	$8E6	10128	Reference to the a Impt file of level 0
+Footstep run start impact	$968	10128	Reference to the a Impt file of level 0
+Footstep single step impact	$9EA	10128	Reference to the a Impt file of level 0
+Footstep run stop impact	$A6C	10128	Reference to the a Impt file of level 0
+Footstep walk stop impact	$AEE	10128	Reference to the a Impt file of level 0
+Footstep run sprint impact	$B70	10128	Reference to the a Impt file of level 0
+Unknown	$BF4	10064	special death particles; only the mad bomber use it
+TRBS link	$C3C	8	Body set link
+TRMA link	$C40	8	Texture map array link
+CBPM link	$C44	8	Body part material link
+CBPI link	$C48	8	Body part impact link
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC link	$C88	8	Animation collection link
+TRSC link	$C8C	8	Screen (aiming) collection link
Index: /oup/releases/0.30a/StructDefs/SUBT.txt
===================================================================
--- /oup/releases/0.30a/StructDefs/SUBT.txt	(revision 8)
+++ /oup/releases/0.30a/StructDefs/SUBT.txt	(revision 8)
@@ -0,0 +1,5 @@
+Subtitles
+ID	$00	4	ID of this file
+LevelID	$04	8	ID of the level this file is in
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Subtitle count	$1C	4	Number of subtitles in this file
Index: /oup/releases/0.30a/StructDefs/TRAM.txt
===================================================================
--- /oup/releases/0.30a/StructDefs/TRAM.txt	(revision 8)
+++ /oup/releases/0.30a/StructDefs/TRAM.txt	(revision 8)
@@ -0,0 +1,49 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	8	Flags; It seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	8	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	8	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	2	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	10016	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	6	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
Index: /oup/releases/0.30a/StructDefs/TXAN.txt
===================================================================
--- /oup/releases/0.30a/StructDefs/TXAN.txt	(revision 8)
+++ /oup/releases/0.30a/StructDefs/TXAN.txt	(revision 8)
@@ -0,0 +1,14 @@
+Texture Animation
+
+File ID	$00	12	File ID of this file
+Level Number	$04	4
+Unused	$08	1012
+
+Loop speed	$14	2
+Unknown	$16	2
+Unknown	$18	2
+Unused	$1A	1002
+Number of images	$1C	4
+
+*Packages		$20	$1C	4	4
+Image	$0	12
Index: /oup/releases/0.30a/StructDefs/TXMP.txt
===================================================================
--- /oup/releases/0.30a/StructDefs/TXMP.txt	(revision 8)
+++ /oup/releases/0.30a/StructDefs/TXMP.txt	(revision 8)
@@ -0,0 +1,13 @@
+Texture
+ID	$00	12	ID of this file
+LevelID	$04	8	ID of the level this file is in
+FileName	$08	10128	
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	12	Link to the TXAN-file (if this TXMP is the first image of an animation)
+TXMP-Link	$98	12	Link to another TXMP-file
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
Index: /oup/releases/0.30a/blubb.txt
===================================================================
--- /oup/releases/0.30a/blubb.txt	(revision 8)
+++ /oup/releases/0.30a/blubb.txt	(revision 8)
@@ -0,0 +1,6 @@
+___FILEINDEX___.txt
+
+
+TXMP:
+MipMapping: Bit0=an/aus
+ColorDepth: Bit0=??AnimationPic??, Bit1=shade vertex, Bit2=transparency, Bit4=16bit, Bit5=32bit
Index: /oup/releases/0.30a/changelog.txt
===================================================================
--- /oup/releases/0.30a/changelog.txt	(revision 8)
+++ /oup/releases/0.30a/changelog.txt	(revision 8)
@@ -0,0 +1,98 @@
+OniUnPacker v0.30a
+------------------
++Completely rewritten data-backend-connection-classes (Unit15_Classes.pas)
+
+OniUnPacker v0.29a
+------------------
++Little changes in StructureDefs
+
+OniUnPacker v0.29a
+------------------
++New StructureViewer
++New StructureTypes: 12=.dat-file-ID, 13..16=SignedInteger, 1000..9999=Unused data
++Dynamic Structures (look at TXAN-files or AISA-files for examples)
++File-type associations (.dat, .oldb, .opf) with OUP possible
++File IDs as Hex
+
+OniUnPacker v0.28a
+------------------
++StructureDefinitions as separate txt-files
++Minor bugfixes
++Ctrl+C for Hex-fields
+
+OniUnPacker v0.27a
+------------------
++Added MAC-file support
++Added StructureDefs for ONCCs / TRAMs (thanks to SSG)
+
+OniUnPacker v0.26a
+------------------
++Fixed some bugs again ;)
+
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.30a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.30a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.30a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,183 @@
+﻿<?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 Name="UnitInitSeq">True</Compiler>
+			<Compiler Name="LocalPInvoke">True</Compiler>
+			<Compiler Name="CodePage"></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 Name="GenerateHpps">False</Linker>
+		</Linker>
+		<Directories>
+			<Directories Name="OutputDir">exe</Directories>
+			<Directories Name="UnitOutputDir">dcu</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 Name="Debug Symbols Search Path"></Parameters>
+			<Parameters Name="LoadAllSymbols">True</Parameters>
+			<Parameters Name="LoadUnspecifiedSymbols">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>
+		<Language>
+			<Language Name="ActiveLang"></Language>
+			<Language Name="ProjectLang">$00000000</Language>
+			<Language Name="RootDir"></Language>
+		</Language>  <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.30a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.30a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.30a/src/OniUnPacker.cfg	(revision 8)
@@ -0,0 +1,40 @@
+-$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
+-E"exe"
+-N0"dcu"
+-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.30a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.30a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.30a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,32 @@
+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},
+  Unit13_rawedit in 'Unit13_rawedit.pas' {Form13},
+  Unit14_settings in 'Unit14_settings.pas' {Form14},
+  ftypesAPI in 'TFileTypeRegistration\ftypesAPI.pas',
+  Unit15_Classes in 'Unit15_Classes.pas';
+
+{$R *.res}
+{$R icon2.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.CreateForm(TForm12, Form12);
+  Application.CreateForm(TForm14, Form14);
+  Application.Run;
+END.
Index: /oup/releases/0.30a/src/TFileTypeRegistration/IsAdmin.inc
===================================================================
--- /oup/releases/0.30a/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
+++ /oup/releases/0.30a/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
@@ -0,0 +1,90 @@
+function GetAdminSid: PSID;
+const
+  // bekannte SIDs ... (WinNT.h)
+  SECURITYNTAUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
+  // bekannte RIDs ... (WinNT.h)
+  SECURITYBUILTINDOMAINRID: DWORD = $00000020;
+  DOMAINALIASRIDADMINS: DWORD = $00000220;
+begin
+  Result := nil;
+  AllocateAndInitializeSid(SECURITYNTAUTHORITY,
+    2,
+    SECURITYBUILTINDOMAINRID,
+    DOMAINALIASRIDADMINS,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    Result);
+end;
+
+function IsAdmin: LongBool;
+var
+  TokenHandle      : THandle;
+  ReturnLength     : DWORD;
+  TokenInformation : PTokenGroups;
+  AdminSid         : PSID;
+  Loop             : Integer;
+  wv               : TOSVersionInfo;
+begin
+  wv.dwOSVersionInfoSize := sizeof(TOSversionInfo);
+  GetVersionEx(wv);
+
+  Result := (wv.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS);
+
+  if(wv.dwPlatformId = VER_PLATFORM_WIN32_NT) then
+    begin
+      TokenHandle := 0;
+      if OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, TokenHandle) then
+        try
+          ReturnLength := 0;
+          GetTokenInformation(TokenHandle, TokenGroups, nil, 0, ReturnLength);
+          TokenInformation := GetMemory(ReturnLength);
+          if Assigned(TokenInformation) then
+            try
+              if GetTokenInformation(TokenHandle, TokenGroups,
+                TokenInformation, ReturnLength, ReturnLength) then
+              begin
+                AdminSid := GetAdminSid;
+                for Loop := 0 to TokenInformation^.GroupCount - 1 do
+                  begin
+                    if EqualSid(TokenInformation^.Groups[Loop].Sid, AdminSid) then
+                      begin
+                        Result := True; break;
+                      end;
+                  end;
+                FreeSid(AdminSid);
+              end;
+            finally
+              FreeMemory(TokenInformation);
+            end;
+        finally
+          CloseHandle(TokenHandle);
+        end;
+    end;
+end;
+
+function WVersion: string; 
+var 
+  OSInfo: TOSVersionInfo; 
+begin 
+  Result := '3X'; 
+  OSInfo.dwOSVersionInfoSize := sizeof(TOSVERSIONINFO); 
+  GetVersionEx(OSInfo); 
+  case OSInfo.dwPlatformID of 
+    VER_PLATFORM_WIN32S: begin 
+        Result := '3X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_WINDOWS: begin 
+        Result := '9X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_NT: begin 
+        Result := 'NT'; 
+        Exit; 
+      end; 
+  end; //case 
+end;
Index: /oup/releases/0.30a/src/TFileTypeRegistration/SysUtils.inc
===================================================================
--- /oup/releases/0.30a/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
+++ /oup/releases/0.30a/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
@@ -0,0 +1,307 @@
+function fileexists(const szFilename: string): boolean;
+var
+  Handle   : THandle;
+  FindData : TWin32FindData;
+begin
+  Handle := FindFirstFile(pchar(szFilename),FindData);
+  Result := (Handle <> INVALID_HANDLE_VALUE);
+
+  if(Result) then Windows.FindClose(Handle);
+end;
+
+function ExtractFileDrive(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') then
+    begin
+      Result := copy(szFilename,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFilePath(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFileName);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') or
+      (szFileName[i] = '\') then
+    begin
+      Result := copy(szFileName,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFileName(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '\') then
+      break;
+
+    dec(i);
+  end;
+
+  Result := copy(szFilename,i + 1,length(szFilename));
+end;
+
+function CutFileExt(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '.') then
+      break;
+
+    dec(i);
+  end;
+
+  if(i = 0) then Result := szFilename
+    else Result := copy(szFilename,1,i-1);
+end;
+
+function ChangeFileExt(const szFileName, szNewExt: string): string;
+begin
+  Result := CutFileExt(szFileName);
+
+  if(szNewExt[1] <> '.') then Result := Result + '.' + szNewExt
+    else Result := Result + szNewExt;
+end;
+
+function FileSearch(const Name, DirList: string): string;
+var
+  I, P, L: Integer;
+begin
+  Result := Name;
+  P      := 1;
+  L      := length(DirList);
+
+  while(true) do begin
+    if(fileexists(Result)) then exit;
+
+    while(P <= L) and (DirList[P] = ';') do inc(P);
+    if(P > L) then break;
+
+    I := P;
+    while(P <= L) and (DirList[P] <> ';') do inc(P);
+
+    Result   := copy(DirList,I,P-I);
+    if not(Result[length(Result)] in[':','\']) then
+      Result := Result + '\';
+
+    Result := Result + Name;
+  end;
+
+  Result  := '';
+end;
+
+function StrToIntDef(const s: string; const i: integer): integer;
+var
+  code : integer;
+begin
+  Val(s,Result,code); if(code <> 0) then
+                        Result := i;
+end;
+
+function IntToStr(const i: integer): string;
+begin
+  Str(i,Result);
+end;
+
+// -----------------------------------------------------------------------------
+
+function Format(fmt: string; params: array of const): string;
+var
+  pdw1,
+  pdw2 : PDWORD;
+  i    : integer;
+  pc   : PCHAR;
+begin
+  pdw1 := nil;
+
+  if High(params) >= 0 then
+    GetMem(pdw1, (High(params) + 1) * sizeof(Pointer));
+
+  pdw2  := pdw1;
+  for i := 0 to High(params) do
+    begin
+      pdw2^ := PDWORD(@params[i])^;
+      inc(pdw2);
+    end;
+
+  pc := GetMemory(1024);
+  if Assigned(pc) then
+    try
+      SetString(Result, pc, wvsprintf(pc, PCHAR(fmt), PCHAR(pdw1)));
+    finally
+      if (pdw1 <> nil) then FreeMem(pdw1);
+      FreeMem(pc);
+    end
+  else
+    Result := '';
+end;
+
+
+// -----------------------------------------------------------------------------
+
+function UpperCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        Result[i] := UpCase(s[i]);
+    end;
+end;
+
+function LowerCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        case s[i] of
+          'A'..'Z','Ä','Ö','Ü':
+            Result[i] := CHR(BYTE(s[i]) + 32);
+          else
+            Result[i] := s[i];
+        end;
+    end;
+end;
+
+function LoggedUser: string;
+var
+  dwLen  : dword;
+  fTest  : boolean;
+begin
+  Result := '';
+  dwLen  := MAX_PATH; SetLength(Result,dwLen);
+
+  fTest  := GetUserName(@Result[1],dwLen);
+
+  if(not fTest) and (GetLastError = ERROR_MORE_DATA) then begin
+    SetLength(Result,dwLen);
+    fTest := GetUserName(@Result[1],dwLen);
+  end;
+
+  if(fTest) and (Result[1] <> #0) then
+    SetLength(Result,dwLen - 1);
+end;
+
+// -----------------------------------------------------------------------------
+
+//
+// delete files during next reboot (code by sakura)
+//
+function DeleteFileDuringNextSystemBoot(aFileName: string): Boolean;
+var
+  ShortName,
+  winini    : string;
+  os        : TOSVersionInfo;
+  ts        : array of string;
+  f         : TextFile;
+  i         : integer;
+begin
+  Result := False;
+
+  // get OS version
+  os.dwOSVersionInfoSize := sizeof(TOSVersionInfo);
+  GetVersionEx(os);
+
+  case os.dwPlatformId of
+    // NT systems
+    VER_PLATFORM_WIN32_NT:
+      Result := MoveFileEx(pchar(aFileName),nil,
+        MOVEFILE_REPLACE_EXISTING + MOVEFILE_DELAY_UNTIL_REBOOT);
+    // 9x systems
+    VER_PLATFORM_WIN32_WINDOWS:
+      begin
+        // get Windows folder
+        SetLength(winini,MAX_PATH+1);
+        SetLength(winini,GetWindowsDirectory(@winini[1],MAX_PATH+1));
+
+        if(winini <> '') then begin
+          if(winini[length(winini)] <> '\') then
+            winini := winini + '\';
+          winini   := winini + 'wininit.ini';
+
+          // get short name of the given file
+          SetLength(ShortName,MAX_PATH+1);
+          SetLength(ShortName,
+            GetShortPathName(@aFilename[1],@ShortName[1],MAX_PATH+1));
+
+          if(ShortName <> '') then begin
+            // add it to "wininit.ini" to delete
+            // during next reboot
+            SetLength(ts,0);
+
+            {$I-}
+            // get old file´s content
+            AssignFile(f,winini);
+            ReSet(f);
+            if(IoResult = 0) then begin
+              while(not eof(f)) do begin
+                SetLength(ts,length(ts)+1);
+                ReadLn(f,ts[length(ts)-1]);
+
+                if(lstrcmpi('[rename]',pchar(ts[length(ts)-1])) = 0) then begin
+                  SetLength(ts,length(ts)+1);
+                  ts[length(ts)-1] := 'NUL='+ShortName;
+                end;
+              end;
+              CloseFile(f);
+            end;
+
+            if(length(ts) = 0) then begin
+              SetLength(ts,2);
+              ts[0] := '[rename]';
+              ts[1] := 'NUL='+ShortName;
+            end;
+
+            // re-create
+            ReWrite(f);
+            Result := (IoResult = 0);
+            if(Result) then begin
+              for i := 0 to length(ts) - 1 do
+                WriteLn(f,ts[i]);
+
+              CloseFile(f);
+            end;
+            {$I+}
+
+            SetLength(ts,0);
+          end;
+        end;
+      end;
+    // only 9x and NT are supported
+    else
+      exit;
+  end;
+end;
Index: /oup/releases/0.30a/src/TFileTypeRegistration/demo.txt
===================================================================
--- /oup/releases/0.30a/src/TFileTypeRegistration/demo.txt	(revision 8)
+++ /oup/releases/0.30a/src/TFileTypeRegistration/demo.txt	(revision 8)
@@ -0,0 +1,34 @@
+uses
+  ftypesAPI;
+
+var
+  ftr    : TFileTypeRegistration;
+  s:String;
+
+
+ftr := TFileTypeRegistration.Create;
+if(ftr <> nil) then begin
+  try
+    if(LOWORD(wp) = IDC_CREATEFOO) then begin
+      if(ftr.RegisterType('.foo','FooFile','FOO-File')) then begin
+        ftr.AddHandler('open','notepad.exe "%1"','Öffnen');
+        ftr.AddHandler('print','notepad.exe /p "%1"');
+        ftr.SetDefaultHandler;
+        ftr.AddNewFileSupport('.foo');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_DELPRINTVERB) then begin
+      if(ftr.GetInternalKey('.foo') <> '') then begin
+        ftr.DeleteHandler('print');
+        ftr.SetDefaultHandler('open');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_REMOVEFOO) then begin
+      s := ftr.GetInternalKey('.foo');
+      if(MessageBox(hwndDlg,pchar('Wollen Sie wirklich ".foo" und "' + s + '" entfernen?'), 'Frage',MB_YESNO or MB_DEFBUTTON2 or MB_ICONQUESTION) = ID_YES) then
+        ftr.UnregisterType('.foo');
+    end;
+  finally
+    ftr.Free;
+  end;
+end;
Index: /oup/releases/0.30a/src/TFileTypeRegistration/ftypesAPI.pas
===================================================================
--- /oup/releases/0.30a/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
+++ /oup/releases/0.30a/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
@@ -0,0 +1,544 @@
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse (Win32-API)
+// Copyright (c) 2004 Mathias Simmack
+//
+// -----------------------------------------------------------------------------
+
+// -- Revision history ---------------------------------------------------------
+//
+//   * erste Version
+//
+// -----------------------------------------------------------------------------
+unit ftypesAPI;
+
+interface
+
+uses
+  Windows, ShlObj;
+
+type
+  TFileTypeRegistration = class
+    FRegConnector : HKEY;
+    FExtension,
+    FInternalName : string;
+    FVerb         : string;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function RegisterType(const Extension, InternalName: string;
+      Description: string = ''; IconFile: string = '';
+      IconIndex: integer = -1): boolean;
+    function UnregisterExtension(const Extension: string): boolean;
+    function UnregisterType(const Extension: string): boolean;
+    procedure UpdateShell;
+    function AddHandler(const HandlerVerb, CommandLine: string;
+      HandlerDescription: string = ''): boolean; overload;
+    function DeleteHandler(const HandlerVerb: string): boolean;
+    function SetDefaultHandler: boolean; overload;
+    function SetDefaultHandler(const HandlerVerb: string): boolean; overload;
+    function GetInternalKey(const Extension: string): string;
+    function AddNewFileSupport(const Extension: string): boolean;
+    function RemoveNewFileSupport(const Extension: string): boolean;
+
+    property Extension: string read FExtension;
+    property InternalName: string read FInternalName;
+    property CurrentVerb: string read FVerb;
+  end;
+
+
+implementation
+
+(* *****************************************************************************
+
+  Beispiel #1: Einen neuen Dateityp registrieren
+  ----------------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // die Dateiendung ".foo" registrieren, der interne Schlüssel
+    // lautet "FooFile", eine Beschreibung und eine Symboldatei
+    // sind ebenfalls angegeben
+    if(ftr.RegisterType('.foo','FooFile','FOO Description',
+      'c:\folder\icon.ico')) then
+    begin
+      // fügt den Handler "open" hinzu und verknüpft ihn mit dem
+      // Programm "foo.exe"
+      ftr.AddHandler('open','"c:\folder\foo.exe" "%1"');
+
+      // setzt den zuletzt benutzten Handler ("open" in dem Fall)
+      // als Standard
+      ftr.SetDefaultHandler;
+    end;
+
+    if(ftr.RegisterType('.foo','ThisIsNotTheFOOKey')) then
+    // Das ist kein Fehler! Obwohl hier der interne Name
+    // "ThisIsNotTheFOOKey" verwendet wird, benutzt die Funktion
+    // intern den bereits vorhandenen Schlüssel "FooFile" (s. oben).
+    begin
+      // zwei neue Handler werden registriert, ...
+      ftr.AddHandler('print','"c:\folder\foo.exe" /p "%1"');
+      ftr.AddHandler('edit','notepad.exe "%1"');
+
+      // ... & dank der überladenen Funktion "SetDefaultHandler"
+      // kann diesmal auch "print" als Standardhandler gesetzt
+      // werden
+      ftr.SetDefaultHandler('print');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #2: Einen neuen Typ mit einem vorhandenen Schlüssel
+  verknüpfen
+  ------------------------------------------------------------
+
+  Das Beispiel registriert die Endung ".foo" auf die gleiche
+  Weise wie Textdateien (.txt). Es wird einfach der interne
+  Schlüsselname ermittelt und für die Endung ".foo" gesetzt
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    strInternalTextFileKey := ftr.GetInternalKey('.txt');
+    if(strInternalTextFileKey <> '') then
+      ftr.RegisterType('.foo',strInternalTextFileKey);
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #3: Einen Handler entfernen
+  ------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // den internen Schlüsselnamen des Typs ".foo" ermitteln, ...
+    if(ftr.GetInternalKey('.foo') <> '') then
+    // ... wobei das Ergebnis in dem Fall unwichtig ist, weil
+    // intern auch die Eigenschaft "FInternalName" gesetzt
+    // wird
+    begin
+      // den "print"-Handler entfernen, ...
+      ftr.DeleteHandler('print');
+
+      // ... & den Standardhandler aktualisieren
+      ftr.SetDefaultHandler('open');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #4: Nur eine Dateiendung entfernen
+  -------------------------------------------
+
+  In diesem Fall wird lediglich die Endung ".foo" entfernt. Der
+  evtl. vorhandene interne Schlüssel bleibt bestehen. Das ist
+  für das Beispiel #2 nützlich, wenn die Endung ".foo" entfernt
+  werden soll, intern aber mit den Textdateien verlinkt ist, die
+  ja im Normalfall nicht entfernt werden dürfen/sollten.
+
+    ftr.UnregisterExtension('.foo');
+
+
+  Beispiel #5: Den kompletten Dateityp entfernen
+  ----------------------------------------------
+
+  Dieses Beispiel entfernt dagegen den kompletten Dateityp,
+  inkl. des evtl. vorhandenen internen Schlüssels (vgl. mit
+  Beispiel #4).
+
+    ftr.UnregisterType('.foo');
+
+  Bezogen auf Beispiel #2 wäre das die fatale Lösung, weil dadurch
+  zwar die Endung ".foo" deregistriert wird, gleichzeitig wird
+  aber auch der intern verwendete Schlüssel der Textdateien
+  gelöscht.
+
+  ALSO, VORSICHT!!!
+
+***************************************************************************** *)
+
+
+//
+// Admin-Rechte sind erforderlich (Funktion von NicoDE)
+//
+{$INCLUDE IsAdmin.inc}
+{$INCLUDE SysUtils.inc}
+
+
+// -----------------------------------------------------------------------------
+//
+// Registry
+//
+// -----------------------------------------------------------------------------
+
+function RegWriteSubKeyVal(const parent: HKEY; SubKeyName: string;
+  ValueName, Value: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := false;
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegCreateKeyEx(parent,pchar(SubKeyName),0,nil,0,KEY_READ or KEY_WRITE,
+    nil,tmp,nil) = ERROR_SUCCESS) then
+  try
+    Result := (RegSetValueEx(tmp,pchar(ValueName),0,REG_SZ,pchar(Value),
+      length(Value) + 1) = ERROR_SUCCESS);
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegReadSubKeyStr(const parent: HKEY; SubKeyName: string;
+  ValueName: string): string;
+var
+  tmp     : HKEY;
+  lpData,
+  dwLen   : dword;
+begin
+  Result  := '';
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegOpenKeyEx(parent,pchar(SubKeyName),0,KEY_READ,
+    tmp) = ERROR_SUCCESS) then
+  try
+    lpData := REG_NONE;
+    dwLen  := 0;
+    if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,nil,
+         @dwLen) = ERROR_SUCCESS) and
+      (lpData in[REG_SZ,REG_EXPAND_SZ]) and
+      (dwLen > 0) then
+    begin
+      SetLength(Result,dwLen);
+
+      if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,
+           @Result[1],@dwLen) = ERROR_SUCCESS) then
+        SetLength(Result,dwLen - 1)
+      else
+        Result := '';
+    end;
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegKeyExists(const parent: HKEY; KeyName: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := (RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,tmp) =
+    ERROR_SUCCESS);
+  if(Result) then RegCloseKey(tmp);
+end;
+
+function RegDeleteWholeKey(parent: HKEY; KeyName: string): boolean;
+var
+  reg       : HKEY;
+  dwSubkeys : dword;
+  dwLen     : dword;
+  i         : integer;
+  buf       : array[0..MAX_PATH]of char;
+begin
+  if(RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,reg) = ERROR_SUCCESS) then
+  try
+    if(RegQueryInfoKey(reg,nil,nil,nil,@dwSubKeys,nil,
+      nil,nil,nil,nil,nil,nil) = ERROR_SUCCESS) and
+      (dwSubKeys > 0) then
+    for i := 0 to dwSubKeys - 1 do begin
+      ZeroMemory(@buf,sizeof(buf));
+      dwLen   := MAX_PATH;
+
+      if(RegEnumKeyEx(reg,i,buf,dwLen,nil,nil,nil,nil) = ERROR_SUCCESS) and
+        (dwLen > 0) then
+      RegDeleteWholeKey(reg,buf);
+    end;
+  finally
+    RegCloseKey(reg);
+  end;
+
+  Result := (RegDeleteKey(parent,pchar(KeyName)) = ERROR_SUCCESS);
+end;
+
+
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse
+//
+// -----------------------------------------------------------------------------
+
+constructor TFileTypeRegistration.Create;
+var
+  key: HKEY;
+  sub: PChar;
+begin
+  FExtension    := '';
+  FInternalName := '';
+  FVerb         := '';
+
+  // Zugriff auf die Registry, & HKEY_CLASSES_ROOT
+  // als Root setzen
+  if(WVersion='9X') or IsAdmin then begin
+    key:=HKEY_CLASSES_ROOT;
+    sub:=nil;
+  end else begin
+    key:=HKEY_CURRENT_USER;
+    sub:=PChar('SOFTWARE\Classes');
+  end;
+
+  if RegOpenKeyEx(key,sub,0,KEY_ALL_ACCESS, FRegConnector) <> ERROR_SUCCESS then
+    FRegConnector := INVALID_HANDLE_VALUE;
+end;
+
+destructor TFileTypeRegistration.Destroy;
+begin
+  if(FRegConnector <> INVALID_HANDLE_VALUE) then
+    RegCloseKey(FRegConnector);
+end;
+
+function TFileTypeRegistration.RegisterType(const Extension,
+  InternalName: string; Description: string = ''; IconFile: string = '';
+  IconIndex: integer = -1): boolean;
+var
+  strDummy : string;
+begin
+  // Standardergebnis
+  Result         := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // ist dieser Typ evtl. schon registriert?
+  strDummy := self.GetInternalKey(Extension);
+
+  // Nein. :o)
+  if(strDummy = '') then strDummy := InternalName;
+
+  // den Schlüssel mit der Dateiendung anlegen oder aktualisieren
+  Result := RegWriteSubKeyVal(FRegConnector,Extension,'',strDummy);
+  if(not Result) then exit;
+
+  // den internen Schlüssel öffnen
+  if(Result) then
+  begin
+    // Beschreibung anlegen
+    if(Description <> '') then
+      RegWriteSubKeyVal(FRegConnector,strDummy,'',Description);
+
+    // Symbol zuweisen (Datei muss existieren!)
+    if(IconFile <> '') and
+      (fileexists(IconFile)) then
+    begin
+      if(IconIndex <> -1) then
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',Format('%s,%d',[IconFile,IconIndex]))
+      else
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',IconFile);
+    end;
+  end;
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+
+  // Properties aktualisieren
+  if(Result) then
+  begin
+    FExtension    := Extension;
+    FInternalName := strDummy;
+  end;
+end;
+
+function TFileTypeRegistration.UnregisterExtension(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // die Endung entfernen
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegDeleteWholeKey(FRegConnector,Extension));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+function TFileTypeRegistration.UnregisterType(const Extension: string):
+  boolean;
+var
+  strDummy : string;
+begin
+  Result   := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // den internen Namen der Endung ermitteln
+  strDummy := self.GetInternalKey(Extension);
+
+  // die Endung entfernen (s. "UnregisterExtension"), ...
+  Result   := (self.UnregisterExtension(Extension)) and
+  // ... & den internen Schlüssel löschen
+    (strDummy <> '') and
+    (RegKeyExists(FRegConnector,strDummy)) and
+    (RegDeleteWholeKey(FRegConnector,strDummy));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+procedure TFileTypeRegistration.UpdateShell;
+begin
+  SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,nil,nil);
+end;
+
+
+const
+  ShellKey = '%s\shell\%s';
+
+function TFileTypeRegistration.AddHandler(const HandlerVerb,
+  CommandLine: string; HandlerDescription: string = ''): boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') or
+    (CommandLine = '') then exit;
+
+  // der interne Schlüssel muss existieren
+  if(RegKeyExists(FRegConnector,FInternalName)) then
+  begin
+    // den Handler (= Verb) erzeugen
+    Result := RegWriteSubKeyVal(FRegConnector,
+      Format(ShellKey + '\command',[FInternalName,HandlerVerb]),
+      '',
+      CommandLine);
+
+    // ggf. Beschreibung für Handler setzen
+    if(HandlerDescription <> '') then
+      RegWriteSubKeyVal(FRegConnector,
+        Format(ShellKey,[FInternalName,HandlerVerb]),
+        '',
+        HandlerDescription);
+  end;
+
+  // interne Eigenschaft anpassen (für "SetDefaultHandler")
+  if(Result) then
+    FVerb := HandlerVerb;
+end;
+
+function TFileTypeRegistration.DeleteHandler(const HandlerVerb: string):
+  boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // Handlerschlüssel entfernen (sofern vorhanden)
+  Result :=
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) and
+    (RegDeleteWholeKey(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb])));
+end;
+
+function TFileTypeRegistration.SetDefaultHandler: boolean;
+begin
+  if(FInternalName <> '') and (FVerb <> '') then
+    Result := self.SetDefaultHandler(FVerb)
+  else
+    Result := false;
+end;
+
+function TFileTypeRegistration.SetDefaultHandler(const HandlerVerb: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // interner Schlüssel muss existieren, ...
+  if(RegKeyExists(FRegConnector,FInternalName)) and
+  // ... & Handler muss existieren, ...
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) then
+  begin
+  // ... dann den Handler als Standard eintragen
+    Result := RegWriteSubKeyVal(FRegConnector,FInternalName + '\shell',
+      '',HandlerVerb);
+  end;
+end;
+
+function TFileTypeRegistration.GetInternalKey(const Extension: string): string;
+begin
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // einen evtl. eingestellten internen Namen zurücksetzen
+  FInternalName   := '';
+
+  // den Schlüssel der Dateiendung öffnen, ...
+  if(RegKeyExists(FRegConnector,Extension)) then
+    FInternalName := RegReadSubKeyStr(FRegConnector,Extension,'');
+
+  // ... als Funktionsergebnis zurückliefern
+  if(not RegKeyExists(FRegConnector,FInternalName)) then
+    FInternalName := '';
+
+  Result := FInternalName;
+end;
+
+
+function TFileTypeRegistration.AddNewFileSupport(const Extension: string):
+  boolean;
+var
+  Description : string;
+begin
+  Result      := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // interne Beschreibung des Typs ermitteln
+  if(self.GetInternalKey(Extension) <> '') then
+    Description := RegReadSubKeyStr(FRegConnector,FInternalName,'')
+  else
+    Description := '';
+
+  // die Beschreibung darf keine Leerzeichen enthalten, weil sie
+  // als Referenz für den neuen Dateinamen verwendet wird, ...
+  if(pos(#32,Description) > 0) or
+  // ... & sie darf auch nicht leer sein
+    (Description = '') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegWriteSubKeyVal(FRegConnector,Extension + '\ShellNew','NullFile',''));
+end;
+
+function TFileTypeRegistration.RemoveNewFileSupport(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension + '\ShellNew')) and
+    (RegDeleteWholeKey(FRegConnector,Extension + '\ShellNew'));
+end;
+
+end.
Index: /oup/releases/0.30a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.30a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.30a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,957 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit9_data_structures;
+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;
+  raw_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.CreateLevel(source,target:String);
+  VAR
+    i:LongWord;
+  BEGIN
+  END;
+
+PROCEDURE TForm10.CreateDatabase(source,target:String);
+{  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+  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:=target;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=loaded_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;
+    IF dat_os_mac THEN
+      Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("os","MAC");'
+    ELSE
+      Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("os","PC");';
+    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:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(dat_header.Files);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    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;
+
+        rawlist:=GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              mem:=TMemoryStream.Create;
+              filestream:=TFileStream.Create(raw_filename,fmOpenRead);
+              filestream.Seek(rawlist[j].raw_addr,soFromBeginning);
+              mem.CopyFrom(filestream,rawlist[j].raw_size);
+              filestream.Free;
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") );';
+              Query.ExecSQL;
+              mem.Free;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        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;
+}begin  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 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 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 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 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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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',False,NIL);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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.30a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+object Form11: TForm11
+  Left = 0
+  Top = 0
+  Caption = 'Extractor'
+  ClientHeight = 398
+  ClientWidth = 487
+  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
+      MultiSelect = True
+      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.30a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.30a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit11_extractor.pas	(revision 8)
@@ -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, Unit15_Classes;
+
+
+PROCEDURE TForm11.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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(OniDataConnection.GetFileIDByName(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+            END ELSE BEGIN
+              ExportFile(OniDataConnection.GetFileIDByName(list.Items.Strings[list.ItemIndex]),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(OniDataConnection.GetFileIDByName(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+          END ELSE BEGIN
+            ExportFile(OniDataConnection.GetFileIDByName(list.Items.Strings[list.ItemIndex]),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.30a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.30a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.30a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,119 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      13..16: BEGIN
+              Exit;
+              edit_new.EditType:=etInteger;
+              edit_new.LimitCheck:=True;
+              edit_new.Max:=Int((Power(256,datatype-13)) / 2)-1;
+              edit_new.Min:=1-Int((Power(256,datatype-13)) / 2)-1;
+            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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.30a/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,324 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  ClientHeight = 640
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = []
+      OnKeyUp = hexKeyUp
+      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 = 600
+      Width = 483
+      Height = 40
+      Align = alBottom
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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 = 374
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 337
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 352
+        Width = 146
+        Height = 88
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        OnResize = panel_extensionResize
+        object lbl_filter: TLabel
+          Left = 2
+          Top = 46
+          Width = 100
+          Height = 17
+          AutoSize = False
+          Caption = 'Filter by &extension:'
+          FocusControl = combo_extension
+        end
+        object combo_extension: TComboBox
+          Left = 2
+          Top = 60
+          Width = 145
+          Height = 21
+          Style = csDropDownList
+          DropDownCount = 12
+          Font.Charset = DEFAULT_CHARSET
+          Font.Color = clWindowText
+          Font.Height = -11
+          Font.Name = 'Tahoma'
+          Font.Style = []
+          ItemHeight = 0
+          ParentFont = False
+          Sorted = True
+          TabOrder = 2
+          OnClick = combo_extensionClick
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.30a/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.30a/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,810 @@
+UNIT Unit13_rawedit;
+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, Unit15_Classes,
+  Menus, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+VAR
+  fileid:LongWord;
+  dat_offset:LongWord;
+  fileid_opened,dat_offset_opened:LongWord;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    IF list_offset.Count=0 THEN BEGIN
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF OniDataConnection.GetFileIDByName(list.Items.Strings[i])=raw_info.src_id THEN BEGIN
+          list.ItemIndex:=i;
+          listClick(Self);
+          Break;
+        END;
+      END;
+      FOR i:=0 TO list_offset.Count-1 DO BEGIN
+        IF MidStr(list_offset.Items.Strings[i],3,8)=IntToHex(raw_info.src_offset,8) THEN BEGIN
+          list_offset.ItemIndex:=i;
+          Break;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    OniDataConnection.LoadRawFile(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+    count:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=OniDataConnection.GetExtensionsList;
+    FOR i:=0 TO High(RawListHandlers) DO BEGIN
+      count:=Length(OniDataConnection.GetFilesList(RawListHandlers[i].Ext,'',True));
+      combo_extension.Items.Add(RawListHandlers[i].ext+' ('+IntToStr(count)+')');
+    END;
+//    FOR i:=0 TO High(exts) DO
+//      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm13.LoadFileNames;
+  VAR
+    Extension:String;
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringArray;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN BEGIN
+      Extension:='';
+      FOR i:=0 TO High(RawListHandlers) DO BEGIN
+        IF Length(Extension)>0 THEN Extension:=Extension+',';
+        Extension:=Extension+RawListHandlers[i].Ext;
+      END;
+    END;
+
+    files:=OniDataConnection.GetFilesList(extension,pattern,TRUE);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=OniDataConnection.GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    list_offset.Enabled:=True;
+    IF OniDataConnection.GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=OniDataConnection.GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,8)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,8));
+    LoadRaw(OniDataConnection.GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of file '+OniDataConnection.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;
+          OniDataConnection.UpdateRawFile(fileid_opened,dat_offset_opened,Length(data),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+{      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+}    END;
+  END;
+
+PROCEDURE TForm13.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  BEGIN
+    saved.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(fileid).Extension+'|All files|*.*';
+    saved.DefaultExt:=OniDataConnection.GetFileInfo(fileid).Extension;
+    IF saved.Execute THEN BEGIN
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.btn_importClick(Sender: TObject);
+  VAR
+    data:Tdata;
+    fs:TFileStream;
+  BEGIN
+    opend.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+*)    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.30a/src/Unit14_settings.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit14_settings.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit14_settings.dfm	(revision 8)
@@ -0,0 +1,75 @@
+object Form14: TForm14
+  Left = 0
+  Top = 0
+  BorderStyle = bsToolWindow
+  Caption = 'Settings'
+  ClientHeight = 350
+  ClientWidth = 250
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object check_filesashex: TCheckBox
+    Left = 8
+    Top = 8
+    Width = 145
+    Height = 17
+    Caption = 'Show filenumbers as Hex'
+    TabOrder = 0
+  end
+  object btn_ok: TButton
+    Left = 8
+    Top = 319
+    Width = 57
+    Height = 23
+    Caption = 'OK'
+    Default = True
+    TabOrder = 1
+    OnClick = btn_okClick
+  end
+  object btn_cancel: TButton
+    Left = 120
+    Top = 319
+    Width = 57
+    Height = 23
+    Cancel = True
+    Caption = 'Cancel'
+    TabOrder = 2
+    OnClick = btn_cancelClick
+  end
+  object btn_register_oldb: TButton
+    Left = 8
+    Top = 128
+    Width = 169
+    Height = 25
+    Caption = 'Register .oldb files with OUP'
+    TabOrder = 3
+    OnClick = btn_register_oldbClick
+  end
+  object btn_register_opf: TButton
+    Left = 8
+    Top = 159
+    Width = 169
+    Height = 25
+    Caption = 'Register .opf files with OUP'
+    TabOrder = 4
+    OnClick = btn_register_opfClick
+  end
+  object btn_register_dat: TButton
+    Left = 8
+    Top = 97
+    Width = 169
+    Height = 25
+    Caption = 'Register .dat files with OUP'
+    TabOrder = 5
+    OnClick = btn_register_datClick
+  end
+end
Index: /oup/releases/0.30a/src/Unit14_settings.pas
===================================================================
--- /oup/releases/0.30a/src/Unit14_settings.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit14_settings.pas	(revision 8)
@@ -0,0 +1,155 @@
+unit Unit14_settings;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils;
+
+type
+  TForm14 = class(TForm)
+    check_filesashex: TCheckBox;
+    btn_ok: TButton;
+    btn_cancel: TButton;
+    btn_register_oldb: TButton;
+    btn_register_opf: TButton;
+    btn_register_dat: TButton;
+    procedure btn_register_opfClick(Sender: TObject);
+    procedure btn_register_oldbClick(Sender: TObject);
+    procedure btn_register_datClick(Sender: TObject);
+    procedure btn_cancelClick(Sender: TObject);
+    procedure btn_okClick(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormShow(Sender: TObject);
+    function RegisterExtension(ext:String):Integer;
+  private
+  public
+  end;
+
+var
+  Form14: TForm14;
+
+implementation
+{$R *.dfm}
+uses
+  Unit1_main, Unit3_data, ftypesAPI;
+
+function ExtensionRegistered(ext:String; var RegisteredAs:String):Boolean;
+  var
+    ftr:TFileTypeRegistration;
+  begin
+    ftr:=TFileTypeRegistration.Create;
+    if(ftr <> nil) then begin
+      try
+        RegisteredAs:=ftr.GetInternalKey(ext);
+        if RegisteredAs<>'' then
+          Result:=True
+        else
+          Result:=False;
+      finally
+        ftr.Free;
+      end;
+    end;
+  end;
+
+function TForm14.RegisterExtension(ext:String):Integer;
+  var
+    ftr:TFileTypeRegistration;
+    temps:String;
+    warnmsg:String;
+  begin
+    Result:=-1;
+    if ExtensionRegistered(ext,temps) then begin
+      if temps<>'ONI'+ext then begin
+        warnmsg:=ext+'-files are not registered to OUP but as "'+temps+'"-files.'+#13+#10+
+                 'Do you really want to unregister'+ext+'-files?';
+        if MessageBox(Self.Handle, PChar(warnmsg),PChar('Warning'),MB_YESNO)=ID_NO then
+          Exit;
+      end;
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then
+        try
+          if not ftr.UnregisterExtension(ext) then
+            ShowMessage('Could not unregister '+ext+'-files')
+          else
+            Result:=2;
+        finally
+          ftr.Free;
+        end;
+    end else begin
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then begin
+        try
+          if ftr.RegisterType(ext,'ONI'+ext,'ONI '+ext+'-file',Application.EXEname+',1') then begin
+            ftr.AddHandler('open','"'+Application.EXEname+'" '+MidStr(ext,2,Length(ext)-1)+' "%1"');
+            ftr.SetDefaultHandler;
+            Result:=1;
+          end;
+        finally
+          ftr.Free;
+        end;
+      end;
+    end;
+  end;
+
+procedure TForm14.btn_cancelClick(Sender: TObject);
+  begin
+    Self.Close;
+  end;
+
+procedure TForm14.btn_okClick(Sender: TObject);
+  begin
+    AppSettings.FilenumbersAsHex:=check_filesashex.Checked;
+    Self.Close;
+  end;
+
+procedure TForm14.btn_register_datClick(Sender: TObject);
+  begin
+    case RegisterExtension('.dat') of
+      2: btn_register_dat.Caption:='Register .dat files with OUP';
+      1: btn_register_dat.Caption:='Unregister .dat files';
+    end;
+  end;
+
+procedure TForm14.btn_register_oldbClick(Sender: TObject);
+  begin
+    case RegisterExtension('.oldb') of
+      2: btn_register_oldb.Caption:='Register .oldb files with OUP';
+      1: btn_register_oldb.Caption:='Unregister .oldb files';
+    end;
+  end;
+
+procedure TForm14.btn_register_opfClick(Sender: TObject);
+  begin
+    case RegisterExtension('.opf') of
+      2: btn_register_opf.Caption:='Register .opf files with OUP';
+      1: btn_register_opf.Caption:='Unregister .opf files';
+    end;
+  end;
+
+procedure TForm14.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  begin
+    CanClose:=False;
+    Self.Visible:=False;
+    Form1.Enabled:=True;
+    Form1.SetFocus;
+  end;
+
+procedure TForm14.FormShow(Sender: TObject);
+  var
+    temps:String;
+  begin
+    if ExtensionRegistered('.dat',temps) then
+      btn_register_dat.Caption:='Unregister .dat files'
+    else
+      btn_register_dat.Caption:='Register .dat files with OUP';
+    if ExtensionRegistered('.oldb',temps) then
+      btn_register_oldb.Caption:='Unregister .oldb files'
+    else
+      btn_register_oldb.Caption:='Register .oldb files with OUP';
+    if ExtensionRegistered('.opf',temps) then
+      btn_register_opf.Caption:='Unregister .opf files'
+    else
+      btn_register_opf.Caption:='Register .opf files with OUP';
+    check_filesashex.Checked:=AppSettings.FilenumbersAsHex;
+  end;
+
+end.
Index: /oup/releases/0.30a/src/Unit15_Classes.pas
===================================================================
--- /oup/releases/0.30a/src/Unit15_Classes.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit15_Classes.pas	(revision 8)
@@ -0,0 +1,874 @@
+unit Unit15_Classes;
+interface
+uses Unit3_data, Unit9_data_structures, Classes, SysUtils, StrUtils, Dialogs, ABSDecUtil, ABSMain, DB;
+
+
+type
+  TOniData = class
+    private
+      FFileName:String;
+      FLevelInfo:TLevelInfo;
+      FBackend:Integer;
+      Fos_mac:Boolean;
+    protected
+    public
+      property FileName:String read FFileName write FFileName; 
+      property Backend:Integer read FBackend write FBackend;
+      property OSisMac:Boolean read Fos_mac write Fos_mac;
+
+      constructor Create(filename:String; var Result:Boolean); virtual; abstract;
+      procedure Close; virtual; abstract;
+
+      function GetFileInfo(fileid:LongWord):TFileInfo; virtual; abstract;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; virtual; abstract;
+      function GetFilesCount:LongWord; virtual; abstract;
+      function GetExtensionsList:TStringArray; virtual; abstract;
+      function GetFileIDByName(name:String):LongWord;
+
+      function LoadDatFile(fileid:LongWord):Tdata; virtual; abstract;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); virtual; abstract;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); virtual; abstract;
+
+      function GetRawList(fileid:LongWord):TRawList; virtual; abstract;
+      function GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); virtual; abstract;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); virtual; abstract;
+      function AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; virtual; abstract;//Returns new Address
+    published
+  end;
+
+  TOniDataDat = class(TOniData)
+    private
+      Fdat_header:THeader;
+      Fdat_filesmap:TFilesMap;
+      Fdat_files:TFiles;
+      Fdat_namedfilesmap:TNamedFilesMap;
+      Fdat_extensionsmap:TExtensionsMap;
+    protected
+    public
+      constructor Create(DatFilename:String; var Result:Boolean); override;
+      procedure Close; override;
+
+      function GetFileInfo(fileid:LongWord):TFileInfo; override;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; override;
+      function GetFilesCount:LongWord; override;
+      function GetExtensionsList:TStringArray; override;
+
+      function LoadDatFile(fileid:LongWord):Tdata; override;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); override;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+
+      procedure LoadRawOffset(loc_sep:Boolean; raw_addr,size:LongWord; target:Pointer);
+      function GetRawList(fileid:LongWord):TRawList; override;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); override;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); override;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      function AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; override;//Returns new Address
+    published
+  end;
+
+  TOniDataADB = class(TOniData)
+    private
+      FDatabase:TABSDatabase;
+      FQuery:TABSQuery;
+    protected
+    public
+      constructor Create(OLDBFilename:String; var Result:Boolean); override;
+      procedure Close; override;
+
+      function GetFileInfo(fileid:LongWord):TFileInfo; override;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; override;
+      function GetFilesCount:LongWord; override;
+      function GetExtensionsList:TStringArray; override;
+
+      function LoadDatFile(fileid:LongWord):Tdata; override;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); override;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+
+      function GetRawList(fileid:LongWord):TRawList; override;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); override;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); override;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+    published
+  end;
+
+
+const
+  ODB_None=-1;
+  ODB_Dat=0;
+  ODB_ADB=1;
+
+var
+  OniDataConnection:TOniData;
+
+function CreateDataConnection(filename:String; backend:Integer):Boolean;
+procedure CloseDataConnection;
+
+
+
+
+implementation
+uses Unit2_Functions;
+
+
+
+(*
+  Implementation of  TOniData
+*)
+
+function TOniData.GetFileIDByName(name:String):LongWord;
+  begin
+    if AppSettings.FilenumbersAsHex then
+      Result:=HexToLong(MidStr(name,1,4))
+    else
+      Result:=StrToInt(MidStr(name,1,5));
+  end;
+
+function TOniData.GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  var
+    i:LongWord;
+    raw_list:TRawList;
+  begin
+    raw_list:=Self.GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    for i:=0 to High(raw_list) do begin
+      if raw_list[i].src_offset=dat_offset then begin
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Result.loc_sep:=raw_list[i].loc_sep;
+        Break;
+      end;
+    end;
+  end;
+
+
+
+
+
+
+
+(*
+================================================================================
+                      Implementation of  TOniDataDat
+*)
+
+constructor TOniDataDat.Create(DatFilename:String; var Result:Boolean);
+  const
+    header_ident1_pc: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_ident1_mac:Array[0..$13] of Byte=
+        ($61,$30,$C1,$23,$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);
+  var
+    i:LongWord;
+    dat_file:TFileStream;
+    header_pc,header_mac:Boolean;
+  begin
+    if not FileExists(DatFilename) then begin
+      ShowMessage('File doesn''t exist!!!');
+      Result:=False;
+      Exit;
+    end;
+    FFileName:=DatFilename;
+    dat_file:=TFileStream.Create(FFileName, fmOpenRead);
+    dat_file.Read(Fdat_header,SizeOf(Fdat_header));
+    header_pc:=True;
+    header_mac:=True;
+    for i:=0 to High(Fdat_header.Ident) do begin
+      FLevelInfo.Ident[i]:=Fdat_header.Ident[i];
+      if Fdat_header.Ident[i]<>header_ident1_pc[i] then begin
+        header_pc:=False;
+      end;
+      if Fdat_header.Ident[i]<>header_ident1_mac[i] then begin
+        header_mac:=False;
+      end;
+    end;
+    if not (header_pc xor header_mac) then begin
+      Result:=False;
+      Exit;
+    end else begin
+      if (header_pc and not header_mac) then
+        Fos_mac:=False
+      else
+        Fos_mac:=True;
+    end;
+    SetLength(Fdat_filesmap,Fdat_header.Files);
+    SetLength(Fdat_files,Fdat_header.Files);
+    for i:=0 to Fdat_header.Files-1 do
+      dat_file.Read(Fdat_filesmap[i],SizeOf(Fdat_filesmap[i]));
+    for i:=0 to Fdat_header.Files-1 do begin
+      Fdat_files[i].Extension:=Fdat_filesmap[i].Extension;
+      Fdat_files[i].Extension:=ReverseString(Fdat_files[i].Extension);
+      Fdat_files[i].Size:=Fdat_filesmap[i].FileSize;
+      Fdat_files[i].FileType:=Fdat_filesmap[i].FileType;
+      Fdat_files[i].DatAddr:=Fdat_filesmap[i].DataAddr-8+Fdat_header.DataAddr;
+      if (Fdat_filesmap[i].FileType and $01)=0 then begin
+        dat_file.Seek(Fdat_filesmap[i].NameAddr+Fdat_header.NamesAddr,soFromBeginning);
+        SetLength(Fdat_files[i].Name,100);
+        dat_file.Read(Fdat_files[i].Name[1],100);
+        Fdat_files[i].Name:=MidStr(Fdat_files[i].Name,1+4,Pos(#0,Fdat_files[i].Name)-1-4);
+      end else begin
+        Fdat_files[i].Name:='';
+      end;
+      Fdat_files[i].FileName:=FormatNumber(i,5,'0')+'-'+Fdat_files[i].Name+'.'+Fdat_files[i].Extension;
+      Fdat_files[i].FileNameHex:=IntToHex(i,4)+'-'+Fdat_files[i].Name+'.'+Fdat_files[i].Extension;
+    end;
+    dat_file.Seek($40+Fdat_header.Files*$14,soFromBeginning);
+    SetLength(Fdat_namedfilesmap,Fdat_header.NamedFiles);
+    for i:=0 to Fdat_header.NamedFiles-1 do
+      dat_file.Read(Fdat_namedfilesmap[i],SizeOf(Fdat_namedfilesmap[i]));
+
+    dat_file.Seek($40+Fdat_header.Files*$14+Fdat_header.NamedFiles*$8,soFromBeginning);
+    SetLength(Fdat_extensionsmap,Fdat_header.Extensions);
+    for i:=0 to Fdat_header.Extensions-1 do
+      dat_file.Read(Fdat_extensionsmap[i],SizeOf(Fdat_extensionsmap[i]));
+
+    dat_file.Seek(Fdat_files[0].DatAddr+7,soFromBeginning);
+    dat_file.Read(FLevelInfo.LevelNumber,1);
+    FLevelInfo.LevelNumber:=FLevelInfo.LevelNumber DIV 2;
+
+    dat_file.Free;
+
+    Result:=True;
+    FBackend:=ODB_Dat;
+  end;
+
+procedure TOniDataDat.Close;
+  begin
+    Self.Free;
+  end;
+
+
+
+function TOniDataDat.GetFileInfo(fileid:LongWord):TFileInfo;
+  begin
+    if fileid<Self.GetFilesCount then
+      Result:=Fdat_files[fileid]
+    else
+      Result.ID:=-1;
+  end;
+
+function TOniDataDat.GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    for i:=0 to Fdat_header.Files-1 do begin
+      if ( (Length(ext)=0) or (Pos(Fdat_files[i].Extension,ext)>0) ) and
+          ( (Length(pattern)=0) or (Pos(UpperCase(pattern),UpperCase(Fdat_files[i].Name))>0) ) then begin
+          if (NoEmptyFiles=false) or ((Fdat_files[i].FileType and $02)=0) then begin
+            SetLength(Result,Length(Result)+1);
+            if AppSettings.FilenumbersAsHex then
+              Result[High(Result)]:=Fdat_files[i].FileNameHex
+            else
+              Result[High(Result)]:=Fdat_files[i].FileName;
+          end;
+      end;
+    end;
+  end;
+
+function TOniDataDat.GetFilesCount:LongWord;
+  begin
+    Result:=Fdat_header.Files;
+  end;
+
+function TOniDataDat.GetExtensionsList:TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    for i:=0 to Fdat_header.Extensions-1 do begin
+      SetLength(Result,Length(Result)+1);
+      with Fdat_extensionsmap[i] do begin
+        Result[High(Result)]:=Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+IntToStr(ExtCount)+')';
+      end;
+    end;
+  end;
+
+
+
+function TOniDataDat.LoadDatFile(fileid:LongWord):Tdata;
+  var
+    dat_file:TFileStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      dat_file:=TFileStream.Create(FFileName, fmOpenRead);
+      dat_file.Seek(Fdat_files[fileid].DatAddr,soFromBeginning);
+      SetLength(Result,Fdat_files[fileid].Size);
+      dat_file.Read(Result[0],Fdat_files[fileid].Size);
+      dat_file.Free;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateDatFile(fileid:LongWord; data:Tdata);
+  var
+    dat_file:TFileStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      dat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      dat_file.Seek(Fdat_files[fileid].DatAddr,soFromBeginning);
+      dat_file.Write(data[0],Length(data));
+      dat_file.Free;
+    end;
+  end;
+
+procedure TOniDataDat.LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  var
+    dat_file:TFileStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      dat_file:=TFileStream.Create(FFileName, fmOpenRead);
+      dat_file.Seek(Fdat_files[fileid].DatAddr+offset,soFromBeginning);
+      dat_file.Read(target^,size);
+      dat_file.Free;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  var
+    dat_file:TFileStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      dat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      dat_file.Seek(Fdat_files[fileid].DatAddr+offset,soFromBeginning);
+      dat_file.Write(target^,size);
+      dat_file.Free;
+    end;
+  end;
+
+
+
+function TOniDataDat.GetRawList(fileid:LongWord):TRawList;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    for i:=0 to High(RawListHandlers) do
+      if UpperCase(RawListHandlers[i].Ext)=UpperCase(Fdat_files[fileid].extension) then
+        if RawListHandlers[i].needed then begin
+          Result:=RawListHandlers[i].Handler(fileid);
+          Break;
+        end else
+          Break;
+  end;
+
+procedure TOniDataDat.LoadRawOffset(loc_sep:Boolean; raw_addr,size:LongWord; target:Pointer);
+  var
+    filestream:TFileStream;
+  begin
+    if not loc_sep then
+      filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenRead)
+    else
+      filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenRead);
+    if raw_addr<=filestream.Size then begin
+      filestream.Seek(raw_addr,soFromBeginning);
+      filestream.Read(target^,size);
+    end;
+    filestream.Free;
+  end;
+
+procedure TOniDataDat.LoadRawFile(fileid,dat_offset:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+    filestream:TFileStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then
+        filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenRead)
+      else
+        filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenRead);
+      filestream.Seek(raw_info.raw_addr,soFromBeginning);
+      filestream.Read(target^,raw_info.raw_size);
+      filestream.Free;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+    filestream:TFileStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then
+        filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite)
+      else
+        filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+      filestream.Seek(raw_info.raw_addr,soFromBeginning);
+      filestream.Write(target^,size);
+      filestream.Free;
+    end;
+  end;
+
+procedure TOniDataDat.LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+    data:Tdata;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      SetLength(data, raw_info.raw_size);
+      Self.LoadRawFile(fileid,dat_offset,@data[0]);
+      mem:=TMemoryStream.Create;
+      mem.Write(data[offset],size);
+      mem.Read(target^,size);
+      mem.Free;  
+    end;
+  end;
+
+procedure TOniDataDat.UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+    filestream:TFileStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then
+        filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite)
+      else
+        filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+      filestream.Seek(raw_info.raw_addr+offset,soFromBeginning);
+      filestream.Write(target^,size);
+      filestream.Free;
+    end;
+  end;
+
+function TOniDataDat.AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; //Returns new Address
+  var
+    filestream:TFileStream;
+  begin
+    if not loc_sep then
+      filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite)
+    else
+      filestream:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+    Result:=filestream.Size;
+    filestream.Seek(0,soFromEnd);
+    filestream.Write(target^,size);
+    filestream.Free;
+  end;
+
+
+
+
+
+
+
+
+
+  
+
+(*
+================================================================================
+                     Implementation of  TOniDataADB
+*)
+
+constructor TOniDataADB.Create(OLDBFilename:String; var Result:Boolean);
+  var
+    i,j:Byte;
+    temps:String;
+  begin
+    if not FileExists(OLDBFilename) then begin
+      ShowMessage('File doesn''t exist!!!');
+      Result:=False;
+      Exit;
+    end;
+    FFileName:=OLDBFilename;
+    FDatabase:=TABSDatabase.Create(nil);
+    FDatabase.DatabaseName:='OLDBcon';
+    FDatabase.DatabaseFileName:=OLDBFilename;
+    FDatabase.Open;
+    FQuery:=TABSQuery.Create(FDatabase);
+    FQuery.DatabaseName:='OLDBcon';
+    FQuery.SQL.Text:='SELECT [name],[value] FROM globals ORDER BY [name] ASC';
+    FQuery.Open;
+    FQuery.First;
+    repeat
+      if FQuery.FieldByName('name').AsString='dbversion' then begin
+        if FQuery.FieldByName('value').AsString<>DBversion then begin
+          ShowMessage('Database-file '+#13+#10+
+                      '"'+OLDBFilename+'"'+#13+#10+
+                      'has wrong version. (Required: '+DBversion+'; found: '+
+                        FQuery.FieldByName('value').AsString+')');
+          FQuery.Close;
+          Result:=False;
+          Exit;
+        end;
+      end;
+      if FQuery.FieldByName('name').AsString='lvl' then begin
+        FLevelInfo.LevelNumber:=StrToInt(FQuery.FieldByName('value').AsString);
+      end;
+      if FQuery.FieldByName('name').AsString='ident' then begin
+        temps:=FQuery.FieldByName('value').AsString;
+        for i:=0 to High(FLevelInfo.Ident) do begin
+          j:=i*2+1;
+          case temps[j] of
+            '0'..'9': FLevelInfo.Ident[i]:=Ord(temps[j])-48;
+            'A'..'F': FLevelInfo.Ident[i]:=Ord(temps[j])-55;
+          end;
+          FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]*16;
+          case temps[j+1] of
+            '0'..'9': FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]+Ord(temps[j+1])-48;
+            'A'..'F': FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]+Ord(temps[j+1])-55;
+          end;
+        end;
+      end;
+      if FQuery.FieldByName('name').AsString='ident' then begin
+        temps:=FQuery.FieldByName('value').AsString;
+        Fos_mac:=temps='MAC';
+      end;
+      FQuery.Next;
+    until FQuery.EoF;
+    FQuery.Close;
+
+    Result:=True;
+    FBackend:=ODB_ADB;
+  end;
+
+procedure TOniDataADB.Close;
+  begin
+    FDatabase.Close;
+    FDatabase.Free;
+    Self.Free;
+  end;
+
+
+
+function TOniDataADB.GetFileInfo(fileid:LongWord):TFileInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT * FROM datfiles WHERE id='+IntToStr(fileid)+' ORDER BY id ASC;';
+      FQuery.Open;
+      if FQuery.RecordCount=1 then begin
+        FQuery.First;
+        Result.ID:=FQuery.FieldByName('id').AsInteger;
+        Result.Name:=FQuery.FieldByName('name').AsString;
+        Result.Extension:=FQuery.FieldByName('extension').AsString;
+        Result.FileName:=FormatNumber(Result.ID,5,'0')+'-'+Result.Name+'.'+Result.Extension;
+        Result.Size:=FQuery.FieldByName('size').AsInteger;
+        Result.FileType:=FQuery.FieldByName('contenttype').AsInteger;
+        Result.DatAddr:=0;
+        Result.opened:=False;
+      end;
+      FQuery.Close;
+    end else begin
+      Result.ID:=-1;
+    end;
+  end;
+
+function TOniDataADB.GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray;
+  var
+    i:LongWord;
+    where:String;
+    where_ext:String;
+  begin
+    where:='';
+    if Length(ext)>0 then begin
+      if Length(where)>0 then
+        where:=where+' AND ';
+      if Pos(',',ext)>0 then begin
+        i:=1;
+        where_ext:='';
+        while i<Length(ext) do begin
+          if Length(where_ext)>0 then
+            where_ext:=where_ext+' OR ';
+          where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")';
+          i:=i+5;
+        end;
+        where:=where+'('+where_ext+')';
+      end else begin
+        where:=where+'(extension="'+ext+'")';
+      end;
+    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;
+    FQuery.SQL.Text:='SELECT id,name,extension FROM datfiles'+where+' ORDER BY id ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i]:=FormatNumber(FQuery.FieldByName('id').AsInteger,5,'0')+'-'+FQuery.FieldByName('name').AsString+'.'+FQuery.FieldByName('extension').AsString;
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetFilesCount:LongWord;
+  begin
+    FQuery.SQL.Text:='SELECT Count(*) AS cnumber FROM datfiles;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      Result:=FQuery.FieldByName('cnumber').AsInteger;
+    end else Result:=0;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetExtensionsList:TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    FQuery.SQL.Text:='SELECT extension,count(extension) AS x FROM datfiles GROUP BY extension ORDER BY extension ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i]:=FQuery.FieldByName('extension').AsString+' ('+IntToStr(FQuery.FieldByName('x').AsInteger)+')';
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+
+
+
+function TOniDataADB.LoadDatFile(fileid:LongWord):Tdata;
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';';
+      FQuery.Open;
+      if FQuery.RecordCount>0 then begin
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        SetLength(Result,mem.Size);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(Result[0],mem.Size);
+        mem.Free;
+      end;
+      FQuery.Close;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateDatFile(fileid:LongWord; data:Tdata);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE datfiles SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE id='+IntToStr(fileid)+';';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+procedure TOniDataADB.LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';';
+      FQuery.Open;
+      IF FQuery.RecordCount>0 THEN BEGIN
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        mem.Seek(offset,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+      FQuery.Close;
+    END;
+  END;
+
+procedure TOniDataADB.UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+    data:Tdata;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      data:=Self.LoadDatFile(fileid);
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(offset,soFromBeginning);
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE datfiles SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE id='+IntToStr(fileid)+';';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+
+
+function TOniDataADB.GetRawList(fileid:LongWord):TRawList;
+  var
+    i:LongWord;
+    Query:TABSQuery;
+  begin
+    SetLength(Result,0);
+    FQuery.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i].src_id:=fileid;
+        Result[i].src_offset:=FQuery.FieldByName('src_link_offset').AsInteger;
+        Result[i].raw_addr:=0;
+        Result[i].raw_size:=FQuery.FieldByName('size').AsInteger;
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+  
+procedure TOniDataADB.LoadRawFile(fileid,dat_offset:LongWord; target:Pointer);
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.Open;
+      if FQuery.RecordCount>0 then begin
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      end;
+      FQuery.Close;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE rawmap SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+procedure TOniDataADB.LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    data:Tdata;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      SetLength(data, Self.GetRawInfo(fileid,dat_offset).raw_size);
+      Self.LoadRawFile(fileid,dat_offset,@data[0]);
+      mem:=TMemoryStream.Create;
+      mem.Write(data[offset],size);
+      mem.Read(target^,size);
+      mem.Free;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+    data:Tdata;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      SetLength(data, Self.GetRawInfo(fileid,offset).raw_size);
+      Self.LoadRawFile(fileid,offset,@data[0]);
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(offset,soFromBeginning);
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE rawmap SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+
+
+
+
+
+
+
+
+
+
+function CreateDataConnection(filename:String; backend:Integer):Boolean;
+  var
+    answer:Boolean;
+  begin
+    if Assigned(OniDataConnection) then begin
+      OniDataConnection.Close;
+      OniDataConnection.Free;
+      OniDataConnection:=Nil;
+    end;
+    case backend of
+      ODB_Dat: OniDataConnection:=TOniDataDat.Create(filename, answer);
+      ODB_ADB: OniDataConnection:=TOniDataADB.Create(filename, answer);
+    else
+      ShowMessage('Unknown Backend');
+      Result:=False;
+      Exit;
+    end;
+
+    if answer then begin
+//      ShowMessage('file loaded');
+//      ShowMessage('Files: '+IntToStr(OniDataConnection.GetFilesCount));
+      Result:=True;
+    end else begin
+      ShowMessage('File not loaded');
+      OniDataConnection.Close;
+      OniDataConnection.Free;
+      Result:=False;
+    end;
+  end;
+
+procedure CloseDataConnection;
+  begin
+    if Assigned(OniDataConnection) then begin
+      OniDataConnection.Close;
+      OniDataConnection:=Nil;
+    end;
+  end;
+
+end.
Index: /oup/releases/0.30a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,194 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  Caption = 'Form1'
+  ClientHeight = 476
+  ClientWidth = 577
+  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 = 459
+    Width = 577
+    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
+    ExplicitTop = 527
+    ExplicitWidth = 692
+  end
+  object tabs: TTabSet
+    Left = 0
+    Top = 439
+    Width = 577
+    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
+    ExplicitTop = 507
+    ExplicitWidth = 692
+  end
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 328
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 424
+    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_CloseFileDB: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = menu_CloseFileDBClick
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_settings: TMenuItem
+        Caption = 'Se&ttings...'
+        OnClick = menu_settingsClick
+      end
+      object menu_sep4: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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
+    object menu_About: TMenuItem
+      Caption = '&About'
+      OnClick = menu_AboutClick
+    end
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 376
+  end
+end
Index: /oup/releases/0.30a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.30a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,527 @@
+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, Unit9_data_structures,
+  Unit10_leveldb, Unit4_exporters, Unit14_settings,
+  Unit5_preview, Unit7_txmpreplace, Unit8_binedit, Unit11_extractor, Unit13_rawedit,
+  Unit15_Classes;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    menu_CloseFileDB: TMenuItem;
+    menu_sep4: TMenuItem;
+    menu_settings: TMenuItem;
+    menu_About: TMenuItem;
+    FUNCTION TryCloseAll:Boolean;
+    procedure menu_AboutClick(Sender: TObject);
+    PROCEDURE menu_settingsClick(Sender: TObject);
+    PROCEDURE menu_CloseFileDBClick(Sender: TObject);
+    PROCEDURE menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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);
+    PROCEDURE UpdateStatBar;
+  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;
+
+    IF MidStr(ParamStr(1),1,3)='opf' THEN BEGIN
+      ShowMessage('Load OPF-File: '+ParamStr(2));
+    END ELSE IF MidStr(ParamStr(1),1,4)='oldb' THEN BEGIN
+      IF NOT CreateDataConnection(ParamStr(2), ODB_ADB) THEN
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an OniUnPacker-LevelDatabase-file?');
+    END ELSE IF MidStr(ParamStr(1),1,3)='dat' THEN BEGIN
+      IF NOT CreateDataConnection(ParamStr(2), ODB_Dat) THEN
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an Oni-.dat-file?');
+    END;
+    UpdateStatBar;
+  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;
+
+
+PROCEDURE TForm1.UpdateStatBar;
+  BEGIN
+    IF Assigned(OniDataConnection) THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(OniDataConnection.FileName)+')';
+      menu_tools.Enabled:=True;
+      menu_convert.Enabled:=False;
+      statbar.Panels.Items[1].Text:='Files: '+IntToStr(OniDataConnection.GetFilesCount);
+      statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(OniDataConnection.GetExtensionsList));
+      CASE OniDataConnection.Backend OF
+        ODB_Dat:
+          BEGIN
+            statbar.Panels.Items[0].Text:='.dat loaded: '+OniDataConnection.FileName;
+          END;
+        ODB_ADB:
+          BEGIN
+            statbar.Panels.Items[0].Text:='OLDB loaded: '+OniDataConnection.FileName;
+          END;
+      ELSE
+        Form1.Caption:='Oni Un/Packer '+version;
+        statbar.Panels.Items[0].Text:='Nothing loaded';
+        statbar.Panels.Items[1].Text:='Files: -';
+        statbar.Panels.Items[2].Text:='Extensions: -';
+        menu_tools.Enabled:=False;
+        menu_convert.Enabled:=True;
+      END;
+    END ELSE BEGIN
+      Form1.Caption:='Oni Un/Packer '+version;
+      statbar.Panels.Items[0].Text:='Nothing loaded';
+      statbar.Panels.Items[1].Text:='Files: -';
+      statbar.Panels.Items[2].Text:='Extensions: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+
+
+FUNCTION TForm1.TryCloseAll:Boolean;
+  BEGIN
+    menu_windows_closeallClick(Self);
+    IF Length(tablist)=0 THEN
+      Result:=True
+    ELSE
+      Result:=False;
+  END;
+
+
+{#################################}
+{##### Main-Menu-Handlers    #####}
+{#################################}
+PROCEDURE TForm1.menu_loaddatClick(Sender: TObject);
+  VAR i:LongWord;
+    answer:Boolean;
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      opend.InitialDir:=AppSettings.DatPath;
+      opend.Filter:='Oni-Dat-Files|*.dat';
+      IF opend.Execute THEN BEGIN
+        IF NOT CreateDataConnection(opend.FileName, ODB_Dat) THEN
+          ShowMessage('Error while loading the file:'+CrLf+opend.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+        AppSettings.DatPath:=ExtractFilepath(opend.FileName);
+      END;
+    END;
+    UpdateStatBar;
+  END;
+PROCEDURE TForm1.menu_lvldbClick(Sender: TObject);
+  VAR answer:Boolean;
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      opend.InitialDir:=AppSettings.DatPath;
+      opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+      IF opend.Execute THEN BEGIN
+        IF NOT CreateDataConnection(opend.FileName, ODB_ADB) THEN
+          ShowMessage('Error while loading the file:'+CrLf+opend.FileName+CrLf+'Perhaps not an OniUnPacker-LevelDatabase-file?');
+        AppSettings.DatPath:=ExtractFilepath(opend.FileName);
+      END;
+    END;
+    UpdateStatBar;
+  END;
+PROCEDURE TForm1.menu_CloseFileDBClick(Sender: TObject);
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      UpdateStatBar;
+    END;
+  END;
+PROCEDURE TForm1.menu_settingsClick(Sender: TObject);
+  BEGIN
+    Form14.Visible:=True;
+    Self.Enabled:=False;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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.menu_AboutClick(Sender: TObject);
+  begin
+    ShowMessage('Will be implemented later ;)');
+  end;
+
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.30a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.30a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,247 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data;
+
+TYPE
+  TExportSet=SET OF (DO_dat,DO_raw,DO_convert,DO_toone);
+
+FUNCTION HexToLong(hex:String):LongWord;
+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 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;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringArray;
+
+
+IMPLEMENTATION
+USES Unit4_Exporters, Unit15_Classes;
+
+TYPE
+  TValueSwitcher=Record
+    CASE IsFloat: Boolean OF
+      True: (ValueFloat:Single);
+      False: (ValueInt:LongWord);
+  END;
+
+
+FUNCTION HexToLong(hex:String):LongWord;
+  FUNCTION NormalizeHexString(VAR hex:String):Boolean;
+    VAR
+      i:Byte;
+    BEGIN
+      IF hex[1]='$' THEN BEGIN
+        FOR i:=1 TO Length(hex)-1 DO BEGIN
+          hex[i]:=hex[i+1];
+        END;
+        SetLength(hex, Length(hex)-1);
+      END;
+      IF (hex[1]='0') AND (UpCase(hex[2])='X') THEN BEGIN
+        FOR i:=1 TO Length(hex)-2 DO BEGIN
+          hex[i]:=hex[i+2];
+        END;
+        SetLength(hex, Length(hex)-2);
+      END;
+      IF Length(hex)=0 THEN
+        Result:=False
+      ELSE
+        Result:=True;
+    END;
+  VAR
+    i:Byte;
+  BEGIN
+    IF NormalizeHexString(hex) THEN BEGIN
+      hex:=UpperCase(hex);
+      Result:=0;
+      FOR i:=1 TO Length(hex) DO BEGIN
+        Result:=Result SHL 4;
+        CASE hex[i] OF
+          '0'..'9': Result:=Result+Ord(hex[i])-48;
+          'A'..'F': Result:=Result+Ord(hex[i])-55;
+        ELSE
+          Result:=0;
+          Exit;
+        END;
+      END;
+    END ELSE BEGIN
+      Result:=0;
+    END;
+  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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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 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;
+    rawlist:TRawList;
+  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
+        rawlist:=OniDataConnection.GetRawList(fileid);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR i:=0 TO High(rawlist) DO BEGIN
+            ExportRawFile(fileid,rawlist[i].src_offset,path+'\'+GetWinFileName(filename));
+          END;
+        END;
+      END;
+    END;
+  END;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringArray;
+  VAR
+    start,len:Word;
+  BEGIN
+    SetLength(Result, 0);
+    start:=1;
+    WHILE PosEx(delimiter,_string,start)>0 DO BEGIN
+      len:=PosEx(delimiter,_string,start)-start;
+      SetLength(Result, Length(Result)+1);
+      Result[High(Result)]:=MidStr(_string,start,len);
+      start:=start+len+1;
+    END;
+    SetLength(Result, Length(Result)+1);
+    Result[High(Result)]:=MidStr(_string,start,Length(_string)-start+1);
+  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;
+
+
+END.
Index: /oup/releases/0.30a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.30a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,122 @@
+unit Unit3_data;
+interface
+uses Classes;
+
+const
+  Version:String='v0.29a';
+  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:Integer;
+    FileName:String;
+    FileNameHex: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;
+
+  TLevelInfo=Record
+    Ident:Array[0..$13] of Byte;
+    LevelNumber:Byte;
+  end;
+
+  TAppSettings=Record
+    DatPath:String[250];
+    ExtractPath:String[250];
+    FilenumbersAsHex:Boolean;
+  end;
+
+  TExportHandlers=Record
+    Ext:String[4];
+    needed:Boolean;
+    Handler:Function(fileid:LongWord; filename:String; convert:Boolean):Integer;
+  end;
+
+  TStringArray=Array of String;
+  TExtList=Array of Record
+    Ext:String;
+    count:LongWord;
+  end;
+
+  TRawInfo=Record
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+    loc_sep:Boolean;
+  end;
+  TRawList=Array of TRawInfo;
+
+var
+
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_os_mac:Boolean=False;
+  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_pc: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_ident1_mac:Array[0..$13] of Byte=
+      ($61,$30,$C1,$23,$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.30a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.30a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,218 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, Dialogs, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset: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, Unit9_data_structures, Unit15_Classes;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=OniDataConnection.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;
+
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    SetLength(data, OniDataConnection.GetRawInfo(fileid, dat_offset).raw_size);
+    OniDataConnection.LoadRawFile(fileid,dat_offset,@data[0]);
+    IF FileExists(filename+'.raw0x'+IntToHex(dat_offset,8)) THEN BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd);
+    END ELSE BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),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;
+    OniDataConnection.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);
+        OniDataConnection.LoadRawFile(fileid,$44,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;
+
+    OniDataConnection.LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+
+    OniDataConnection.LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    FOR i:=1 TO linkcount DO BEGIN
+      OniDataConnection.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;
+
+    OniDataConnection.LoadDatFilePart(fileid,$14,SizeOf(loop_speed),@loop_speed);
+    OniDataConnection.LoadDatFilePart(fileid,$16,SizeOf(unknown),@unknown);
+
+    OniDataConnection.LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      OniDataConnection.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.30a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Caption = 'Preview'
+  ClientHeight = 473
+  ClientWidth = 472
+  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.30a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.30a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,283 @@
+UNIT Unit5_preview;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Math, ExtCtrls, StdCtrls, StrUtils, Menus,
+  Unit2_functions, Unit3_data, Unit4_exporters, Unit6_imgfuncs, Unit15_Classes;
+
+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:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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:=OniDataConnection.GetFileIDByName(list.Items.Strings[list.ItemIndex]);
+    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
+    OniDataConnection.LoadDatFilePart(_fileid,$14,SizeOf(loop_speed),@loop_speed);
+    OniDataConnection.LoadDatFilePart(_fileid,$1C,SizeOf(linkcount),@linkcount);
+    SetLength(memstreams,linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      OniDataConnection.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 '+OniDataConnection.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 '+OniDataConnection.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 '+OniDataConnection.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.30a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.30a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,409 @@
+UNIT Unit6_imgfuncs;
+INTERFACE
+USES Math, Dialogs, SysUtils, Unit3_data, Unit15_Classes;
+
+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; VAR faded:Tdata):Boolean;
+
+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*(imgdepth DIV 8))+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
+    OniDataConnection.LoadDatFilePart(fileid,$10,SizeOf(Result.imgx),@Result.imgx);
+    OniDataConnection.LoadDatFilePart(fileid,$12,SizeOf(Result.imgy),@Result.imgy);
+    OniDataConnection.LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    OniDataConnection.LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    SetLength(images_decoded,linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      OniDataConnection.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;
+  VAR
+    img_addr:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$8C,SizeOf(Result.imgx),@Result.imgx);
+    OniDataConnection.LoadDatFilePart(fileid,$8E,SizeOf(Result.imgy),@Result.imgy);
+    OniDataConnection.LoadDatFilePart(fileid,$90,SizeOf(Result.storetype),@Result.storetype);
+    IF NOT dat_os_mac THEN
+      OniDataConnection.LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr)
+    ELSE
+      OniDataConnection.LoadDatFilePart(fileid,$A0,SizeOf(img_addr),@img_addr);
+
+    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);
+
+    IF NOT dat_os_mac THEN
+      OniDataConnection.LoadRawFile(fileid,$9C,@Result.imgdata[0])
+    ELSE
+      OniDataConnection.LoadRawFile(fileid,$A0,@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; VAR faded:Tdata):Boolean;
+  VAR
+    i:LongWord;
+    x,y:Word;
+    imgdata:Tdata;
+    fadelvldata:Tdata;
+  BEGIN
+    Result:=False;
+    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,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) OR ((x MOD 2)=1) OR ((y MOD 2)=1);
+    IF (x>1) AND (y>1) THEN Exit;
+    Result:=True;
+    SetLength(faded, Length(imgdata));
+    FOR i:=0 TO Length(imgdata)-1 DO faded[i]:=imgdata[i];
+  END;
+
+END.
Index: /oup/releases/0.30a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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 = 'MIP Mapping'
+      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.30a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.30a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,225 @@
+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, Unit15_Classes;
+{$R *.dfm}
+VAR
+  actual_bmpdata:Tdata;
+
+PROCEDURE TForm7.Recreatelist;
+  VAR
+    files:TStringArray;
+    i:LongWord;
+  BEGIN
+    list_txmp.Items.Clear;
+    files:=OniDataConnection.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:=OniDataConnection.GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+
+    OniDataConnection.LoadDatFilePart(id,$88,SizeOf(fadingbyte),@fadingbyte);
+    OniDataConnection.LoadDatFilePart(id,$89,SizeOf(depthbyte),@depthbyte);
+    OniDataConnection.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;
+    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:=OniDataConnection.GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+      OniDataConnection.LoadDatFilePart(id,$8C,2,@oldwidth);
+      OniDataConnection.LoadDatFilePart(id,$8E,2,@oldheight);
+      OniDataConnection.LoadDatFilePart(id,$88,1,@oldfading);
+      OniDataConnection.LoadDatFilePart(id,$89,1,@olddepth);
+      OniDataConnection.LoadDatFilePart(id,$90,1,@oldstore);
+      OniDataConnection.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;
+
+      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_fading.Checked THEN
+        IF Not CreateFadedImage(imgpkg,imgpkg.imgdata) THEN
+          IF MessageBox(Self.Handle, PChar('Can not create a MipMapped-image (probably because of a wrong dimension).'+#13+#10+'Do you want to continue without MipMapping?'), PChar('Warning'), MB_YESNO)=ID_YES THEN
+            check_fading.Checked:=False
+          ELSE
+            Exit;
+
+      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) AND (OniDataConnection.Backend=ODB_Dat) THEN
+        new_rawaddr:=OniDataConnection.AppendRawFile(False,Length(imgpkg.imgdata),imgpkg.imgdata)
+      ELSE BEGIN
+        new_rawaddr:=old_rawaddr;
+        OniDataConnection.UpdateRawFile(id,$9C,Length(imgpkg.imgdata),imgpkg.imgdata); 
+      END;
+
+      datbyte:=$00;
+      IF check_fading.Checked THEN datbyte:=datbyte OR $01;
+      OniDataConnection.UpdateDatFilePart(id,$88,1,@datbyte);
+      datbyte:=$10;
+      IF check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      OniDataConnection.UpdateDatFilePart(id,$89,1,@datbyte);
+      OniDataConnection.UpdateDatFilePart(id,$8C,2,@imgpkg.imgx);
+      OniDataConnection.UpdateDatFilePart(id,$8E,2,@imgpkg.imgy);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      OniDataConnection.UpdateDatFilePart(id,$90,1,@datbyte);
+      OniDataConnection.UpdateDatFilePart(id,$9C,4,@new_rawaddr);
+
+      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(OniDataConnection.GetFileIDByName(list_txmp.Items.Strings[list_txmp.ItemIndex]));
+      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.30a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.30a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.30a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,385 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 555
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 555
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+    ExplicitHeight = 423
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 555
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    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 = 450
+      Width = 483
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitTop = 375
+    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 = []
+      OnKeyUp = hexKeyUp
+      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 value_viewer: TWrapGrid
+      Left = 0
+      Top = 218
+      Width = 483
+      Height = 232
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      PopupMenu = value_viewer_context
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+    object VST: TVirtualStringTree
+      Left = 0
+      Top = 458
+      Width = 483
+      Height = 97
+      Align = alBottom
+      AnimationDuration = 0
+      AutoExpandDelay = 300
+      BiDiMode = bdLeftToRight
+      Colors.UnfocusedSelectionColor = clGradientActiveCaption
+      Colors.UnfocusedSelectionBorderColor = clGradientActiveCaption
+      Ctl3D = True
+      DragOperations = []
+      DrawSelectionMode = smBlendedRectangle
+      EditDelay = 200
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      Header.AutoSizeIndex = 0
+      Header.Font.Charset = DEFAULT_CHARSET
+      Header.Font.Color = clWindowText
+      Header.Font.Height = -11
+      Header.Font.Name = 'Tahoma'
+      Header.Font.Style = []
+      Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoVisible]
+      Header.PopupMenu = VTHPopup
+      Header.Style = hsFlatButtons
+      HintAnimation = hatNone
+      HintMode = hmTooltip
+      Indent = 14
+      ParentBiDiMode = False
+      ParentCtl3D = False
+      ParentFont = False
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 2
+      TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning]
+      TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowRoot, toShowTreeLines, toShowVertGridLines, toUseBlendedImages]
+      TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect]
+      OnDblClick = VSTDblClick
+      OnFocusChanged = VSTFocusChanged
+      OnGetText = VSTGetText
+      OnHeaderDragged = VSTHeaderDragged
+      Columns = <
+        item
+          MaxWidth = 300
+          MinWidth = 100
+          Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 0
+          Spacing = 20
+          Width = 150
+          WideText = 'Name'
+          WideHint = 'Name of the item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 1
+          Spacing = 20
+          Width = 85
+          WideText = 'Offset'
+          WideHint = 'Offset of the data-item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 75
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 2
+          Width = 75
+          WideText = 'Type'
+          WideHint = 'Data type of the item.'
+        end
+        item
+          MaxWidth = 250
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 3
+          Width = 100
+          WideText = 'Value'
+          WideHint = 'Value of the item.'
+        end
+        item
+          MaxWidth = 400
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 4
+          Width = 400
+          WideText = 'Description'
+        end>
+      WideDefaultText = ''
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 555
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Bevel1: TBevel
+      Left = 0
+      Top = 491
+      Width = 150
+      Height = 6
+      Align = alBottom
+      Style = bsRaised
+      ExplicitTop = 359
+    end
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 388
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 388
+      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 = 497
+      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
+  object VTHPopup: TVTHeaderPopupMenu
+    OnColumnChange = VTHPopupColumnChange
+    Left = 200
+    Top = 496
+  end
+end
Index: /oup/releases/0.30a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.30a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,871 @@
+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, Unit15_Classes,
+  Menus, Math, VirtualTrees, VTHeaderPopup;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    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;
+    VST: TVirtualStringTree;
+    VTHPopup: TVTHeaderPopupMenu;
+    procedure VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex);
+    procedure VSTDblClick(Sender: TObject);
+    procedure VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+      const Column: TColumnIndex; Visible: Boolean);
+    procedure VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+      OldPosition: Integer);
+    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE LoadDat(_fileid:LongWord);
+    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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    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 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, Unit13_rawedit;
+VAR
+  fileid:LongWord;
+
+TYPE
+  PNodeData = ^TNodeData;
+  TNodeData = record
+    Caption:String;
+    Offset:LongInt;
+    DataType:Word;
+    Value:String;
+    Description:String;
+  end;
+
+
+function AddVSTEntry(AVST:TCustomVirtualStringTree; ANode:PVirtualNode; ARecord:TNodeData):PVirtualNode;
+  var
+    data:PNodeData;
+  begin
+    Result:=AVST.AddChild(ANode);
+    data:=AVST.GetNodeData(Result);
+    AVST.ValidateNode(Result,False);
+    data^:=ARecord;
+  end;
+
+
+
+PROCEDURE TForm8.LoadDat(_fileid:LongWord);
+  VAR
+    i:LongWord;
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF OniDataConnection.GetFileIDByName(list.Items.Strings[i])=fileid THEN BEGIN
+            list.ItemIndex:=i;
+            Exit;
+          END;
+        END;
+      END;
+    END;
+    fileid:=_fileid;
+    FOR i:=0 TO list.Count-1 DO
+      IF OniDataConnection.GetFileIDByName(list.Items.Strings[i])=fileid THEN BEGIN
+        list.ItemIndex:=i;
+        Break;
+      END;
+    Self.ClearStructViewer;
+    data:=OniDataConnection.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; 
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.listClick(Sender: TObject);
+  BEGIN
+    LoadDat(OniDataConnection.GetFileIDByName(list.Items.Strings[list.ItemIndex]));
+  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]);
+      11: Result:='0x'+IntToHex(OniDataConnection.GetRawInfo(fileid,offset).raw_addr,8);
+      12: Result:=FormatNumber(hex.data[offset+1]+hex.data[offset+2]*256+hex.data[offset+3]*256*256,5,'0');
+      13: Result:=IntToStr(hex.data[offset]);
+      14: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256);
+      15: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256);
+      16: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256);
+      1000..9999: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-1000 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Result:=Result+'.';
+          END;
+        END;
+      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;
+  VAR
+    i,j:LongWord;
+    pdata: PNodeData;
+    data: TNodeData;
+    node: PVirtualNode;
+    structs: TStructDef;
+  BEGIN
+    VST.BeginUpdate;
+    IF VST.RootNodeCount=0 THEN BEGIN
+      structs:=LoadStructureDefinition(fileid);
+      IF structs.data THEN BEGIN
+        IF Length(structs.Global)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Global) DO BEGIN
+            data.Caption:=structs.Global[i].name;
+            data.Offset:=structs.Global[i].offset;
+            data.DataType:=structs.Global[i].datatype;
+            data.Value:=GetValue(structs.Global[i].datatype, structs.Global[i].offset);
+            data.Description:=structs.Global[i].description;
+            AddVSTEntry(VST, nil, data);
+          END;
+        END;
+        IF Length(structs.Subs)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Subs) DO BEGIN
+            WITH structs.Subs[i] DO BEGIN
+              IF Length(Entries)>0 THEN BEGIN
+                IF Pos('#',SubName)>0 THEN BEGIN
+                  data.Offset:=HexToLong(MidStr(SubName, Pos('#',SubName)+1, 8));
+                  data.Value:=MidStr(SubName, PosEx('#',SubName,Pos('#',SubName)+1)+1, 8);
+                  data.Caption:=MidStr(SubName, 1, Pos('#',SubName)-1);
+                  data.Description:=SubDesc;
+                END ELSE BEGIN
+                  data.Caption:=SubName;
+                  data.Description:=SubDesc;
+                  data.Offset:=0;
+                  data.Value:='';
+                END;
+                data.DataType:=0;
+                node:=AddVSTEntry(VST, nil, data);
+                data.Description:='';
+                FOR j:=0 TO High(Entries) DO BEGIN
+                  data.Caption:=Entries[j].name;
+                  data.Offset:=Entries[j].offset;
+                  data.DataType:=Entries[j].datatype;
+                  data.Value:=GetValue(Entries[j].datatype, Entries[j].offset);
+                  data.Description:=Entries[j].description;
+                  AddVSTEntry(VST, node, data);
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      IF VST.RootNodeCount>0 THEN
+        VST.FocusedNode:=VST.GetFirst;
+    END ELSE BEGIN
+      Node:=VST.GetFirst;
+      WHILE Assigned(Node) DO BEGIN
+        pdata:=VST.GetNodeData(Node);
+        IF pdata.DataType>0 THEN
+          pdata.Value:=GetValue(pdata.Datatype, pdata.Offset);
+        Node:=VST.GetNext(Node);
+      END;
+    END;
+    VST.EndUpdate;
+  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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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;
+    VST.NodeDataSize:=SizeOf(TNodeData);
+    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;
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+OniDataConnection.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;
+          OniDataConnection.UpdateDatFile(fileid,data);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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;
+  BEGIN
+    VST.Clear;
+  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.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos;
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm8.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm8.hexSelectionChanged(Sender: TObject);
+  VAR
+    selstart:Integer;
+    node:PVirtualNode;
+    pdata:PNodeData;
+  BEGIN
+    IF hex.DataSize>0 THEN BEGIN
+      WriteValues;
+      selstart:=hex.SelStart;
+      IF VST.RootNodeCount>0 THEN BEGIN
+        Node:=VST.GetFirst;
+        WHILE Assigned(Node) DO BEGIN
+          pdata:=VST.GetNodeData(Node);
+          IF pdata.DataType>0 THEN BEGIN
+            IF ((selstart-pdata.Offset)<GetTypeDataLength(pdata.DataType)) AND ((selstart-pdata.Offset)>=0) THEN BEGIN
+              VST.FocusedNode:=Node;
+              VST.Selected[Node]:=True;
+              Break;
+            END;
+          END;
+          Node:=VST.GetNext(Node);
+        END;
+      END;
+    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 (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(fileid).Extension+'|All files|*.*';
+    saved.DefaultExt:=OniDataConnection.GetFileInfo(fileid).Extension;
+    IF saved.Execute THEN BEGIN
+      ExportDatFile(fileid,saved.FileName);
+    END;
+  END;
+
+PROCEDURE TForm8.btn_importClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  BEGIN
+    opend.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(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
+    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.VSTDblClick(Sender: TObject);
+  var
+    node:PVirtualNode;
+    nodedata:PNodeData;
+  begin
+    if VST.FocusedColumn=3 then begin
+      node:=VST.FocusedNode;
+      nodedata:=VST.GetNodeData(node);
+
+      IF NOT (nodedata.datatype IN [11,12]) THEN BEGIN
+        Form12.MakeVarInput(nodedata.Caption,nodedata.offset,nodedata.datatype,nodedata.value,Self);
+      END ELSE BEGIN
+        IF nodedata.DataType=11 THEN BEGIN
+          IF OniDataConnection.GetRawInfo(fileid,nodedata.offset).raw_size>0 THEN BEGIN
+            IF Form1.open_child('rawedit') THEN BEGIN
+              TForm13(Form1.ActiveMDIChild).LoadRaw(OniDataConnection.GetRawInfo(fileid,nodedata.offset));
+            END;
+          END;
+        END;
+        IF nodedata.DataType=12 THEN BEGIN
+          IF (StrToInt(nodedata.Value)<OniDataConnection.GetFilesCount) AND
+              (StrToInt(nodedata.Value)>0) AND
+              (StrToInt(nodedata.Value)<>fileid) THEN BEGIN
+            IF OniDataConnection.GetFileInfo(StrToInt(nodedata.Value)).Size>0 THEN BEGIN
+              IF Form1.open_child('binedit') THEN BEGIN
+                TForm8(Form1.ActiveMDIChild).LoadDat(StrToInt(nodedata.Value));
+              END;
+            END ELSE BEGIN
+              ShowMessage('Linked filed is a zero-byte-file');
+            END;
+          END;
+        END;
+      END;
+
+    end;
+  end;
+
+procedure TForm8.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex);
+  var
+    data:PNodeData;
+  begin
+    data:=VST.GetNodeData(node);
+    IF data.DataType>0 THEN BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+GetTypeDataLength(data.DataType)-1;
+    END ELSE BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+HexToLong(data.Value)-1;
+    END;
+  end;
+
+procedure TForm8.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+  var
+    data:PNodeData;
+  begin
+    data := Sender.GetNodeData(Node);
+    CellText := '';
+    if TextType = ttNormal then begin
+      case Column of
+        0: CellText := data.Caption;
+        1:
+          if data.DataType>0 then
+            CellText := '0x'+IntToHex(data.Offset,8)
+          else
+            if data.Offset>0 then
+              CellText := '0x'+IntToHex(data.Offset,8);
+        2:
+          if data.DataType>0 then
+            CellText := GetDataType(data.DataType);
+        3:
+          if data.DataType>0 then
+            CellText := GetValue(data.DataType, data.Offset)
+          else
+            if Length(data.Value)>0 then
+              CellText := IntToStr(HexToLong(data.Value))+' Bytes';
+        4:
+          CellText := data.Description;
+      end;
+    end;
+  end;
+
+procedure TForm8.VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+  OldPosition: Integer);
+  begin
+    if Sender.Columns.Items[column].Position<1 then
+      Sender.Columns.Items[column].Position:=OldPosition;
+  end;
+
+procedure TForm8.VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+  const Column: TColumnIndex; Visible: Boolean);
+  begin
+    if column=0 then
+      TVirtualStringTree(Sender).Header.Columns.Items[column].Options:=TVirtualStringTree(Sender).Header.Columns.Items[column].Options+[coVisible];
+  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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+
+END.
Index: /oup/releases/0.30a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.30a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.30a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,455 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, Classes, Unit3_data, Dialogs, StrUtils;
+
+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
+                      // 11    : raw-addr
+                      // 12    : dat-file-ID
+                      // 13..16: Signed Integer[1..4]
+                      // 1000..9999: Unused data[0-8999]
+                      // 10000+: string[0+]
+      description:String;
+    END;
+  TStructDefSub=RECORD
+      SubName:String;
+      SubDesc:String;
+      Entries:Array OF TStructure_entry;
+    END;
+  TStructDef=RECORD
+      Data:Boolean;
+      Global:Array OF TStructure_entry;
+      Subs:Array OF TStructDefSub;
+    END;
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+
+VAR
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+
+IMPLEMENTATION
+USES Unit2_functions, Unit15_Classes, Forms;
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      12: Result:=4;
+      13..16: Result:=datatype-12;
+      1000..9999: Result:=datatype-1000;
+      10000..65535: Result:=datatype-10000;
+    END;
+  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';
+      11: Result:='Raw-Address';
+      12: Result:='.dat-file-ID';
+      13..16: Result:='SignedInt'+IntToStr((typeid-12)*8);
+      1000..9999: Result:='Unused('+IntToStr(typeid-1000)+')';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*4;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*4,4,@link);
+        Result[i].raw_addr:=link;
+        Result[i].raw_size:=0{????????????????????????????????};
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION AKVA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*$74+$24;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*$74+$24,4,@link);
+        Result[i].raw_addr:=link;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*$74+$28,4,@link);
+        Result[i].raw_size:=link;
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    OniDataConnection.LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$08,4,@datasize);
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    IF NOT dat_os_mac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$40,4,@datasize);
+      OniDataConnection.LoadDatFilePart(fileid,$44,4,@link);
+      Result[0].src_offset:=$44;
+    END ELSE BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$10,4,@datasize);
+      OniDataConnection.LoadDatFilePart(fileid,$14,4,@link);
+      Result[0].src_offset:=$14;
+    END;
+    SetLength(Result,1);
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=False;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,lastlink:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$18,4,@baselink);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$20+(links-1)*4,4,@lastlink);
+      SetLength(data,lastlink+1024);
+        TOniDataDat(OniDataConnection).LoadRawOffset(false, baselink,lastlink+1024,data); 
+//      OniDataConnection.LoadRawFile(fileid,$1C,baselink,lastlink+1024,False,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[lastlink+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=lastlink+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    OniDataConnection.LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    OniDataConnection.LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    OniDataConnection.LoadDatFilePart(fileid,$182,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    OniDataConnection.LoadDatFilePart(fileid,$183,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    OniDataConnection.LoadDatFilePart(fileid,$184,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    OniDataConnection.LoadDatFilePart(fileid,$185,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    OniDataConnection.LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    OniDataConnection.LoadDatFilePart(fileid,$186,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    OniDataConnection.LoadDatFilePart(fileid,$187,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    OniDataConnection.LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    OniDataConnection.LoadDatFilePart(fileid,$154,2,@tempw);
+    OniDataConnection.LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    OniDataConnection.LoadDatFilePart(fileid,$138,4,@templ);
+    OniDataConnection.LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    OniDataConnection.LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      TOniDataDat(OniDataConnection).LoadRawOffset(false,link,$FFFF,data); 
+//      OniDataConnection.LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link_pc:LongWord;
+    link_mac:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    OniDataConnection.LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    OniDataConnection.LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    OniDataConnection.LoadDatFilePart(fileid,$9C,4,@link_pc);
+    OniDataConnection.LoadDatFilePart(fileid,$A0,4,@link_mac);
+    CASE storetype OF
+      0,1,2: datasize:=x*y*2;
+      8: datasize:=x*y*4;
+      9: datasize:=x*y DIV 2;
+    END;
+    SetLength(Result,1);
+    IF NOT dat_os_mac THEN BEGIN
+      Result[0].src_offset:=$9C;
+      Result[0].raw_addr:=link_pc
+    END ELSE BEGIN
+      Result[0].src_offset:=$A0;
+      Result[0].raw_addr:=link_mac;
+    END;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=dat_os_mac;
+  END;
+
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+  VAR
+    i:LongWord;
+    current_type:Byte; //0: Global, 1: Undynamic, 2: Dynamic
+    current_base,current_package,current_package_size:LongWord;
+    packages:LongWord;
+    deffile:Text;
+    structentry:TStructure_Entry;
+    fields:TStringArray;
+    filename:String;
+    ext:String[4];
+    temps:String;
+    data:TData;
+  BEGIN
+    SetLength(Result.Global,0);
+    SetLength(Result.Subs,0);
+    Result.Data:=False;
+    ext:=OniDataConnection.GetFileInfo(fileid).Extension;
+    filename:=ExtractFilePath(Application.ExeName)+'\StructDefs\'+ext+'.txt';
+    IF FileExists(filename) THEN BEGIN
+      data:=OniDataConnection.LoadDatFile(fileid);
+      AssignFile(deffile,filename);
+      Reset(deffile);
+      current_type:=0;
+      Result.Data:=True;
+      IF NOT EoF(deffile) THEN BEGIN
+        ReadLn(deffile,temps);
+        WHILE NOT EoF(deffile) DO BEGIN
+          ReadLn(deffile,temps);
+          IF (Length(temps)>0) AND (temps[1]<>'#') THEN BEGIN
+            IF temps[1]='*' THEN BEGIN
+              fields:=Explode(temps,#9);
+              CASE Length(fields) OF
+                1..2: BEGIN
+                     current_type:=1;
+                     current_base:=0;
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                     IF Length(fields)=2 THEN
+                       Result.Subs[High(Result.Subs)].SubDesc:=fields[1];
+                   END;
+                3: BEGIN
+                     current_type:=1;
+                     current_base:=HexToLong(fields[2]);
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                     Result.Subs[High(Result.Subs)].SubDesc:=fields[1];
+                   END;
+                6: BEGIN
+                     current_type:=2;
+                     current_base:=HexToLong(fields[2]);
+                     current_package:=0;
+                     current_package_size:=StrToInt(fields[5]);
+                     IF fields[4][1]<>'$' THEN BEGIN
+                       CASE StrToInt(fields[4]) OF
+                         1: packages:=data[HexToLong(fields[3])];
+                         2: packages:=data[HexToLong(fields[3])]+data[HexToLong(fields[3])+1]*256;
+                         4: packages:=data[HexToLong(fields[3])]+data[HexToLong(fields[3])+1]*256+data[HexToLong(fields[3])+2]*256*256+data[HexToLong(fields[3])+3]*256*256*256;
+                       END;
+                     END ELSE BEGIN
+                       packages:=HexToLong(fields[4]);
+                     END;
+                     SetLength(Result.Subs, Length(Result.Subs)+packages);
+                     FOR current_package:=0 TO packages-1 DO BEGIN
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubName:=
+                           MidStr(fields[0],2,Length(fields[0])-1)+'['+IntToStr(current_package)+']'+
+                           '#'+IntToHex(current_base+current_package*current_package_size,8)+
+                           '#'+IntToHex(current_package_size,8);
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubDesc:=
+                           fields[1];
+                     END;
+                   END;
+              END;
+            END ELSE BEGIN
+              fields:=Explode(temps,#9);
+              IF (Length(fields)=3) OR (Length(fields)=4) THEN BEGIN
+                structentry.name:=fields[0];
+                structentry.datatype:=StrToInt(fields[2]);
+                IF Length(fields)=4 THEN
+                  structentry.description:=fields[3]
+                ELSE
+                  structentry.description:='';
+                IF current_type IN [0,1] THEN BEGIN
+                  structentry.offset:=HexToLong(fields[1])+current_base;
+                  IF Length(Result.Subs)=0 THEN BEGIN
+                    SetLength(Result.Global,Length(Result.Global)+1);
+                    Result.Global[High(Result.Global)]:=structentry;
+                  END ELSE BEGIN
+                    SetLength(Result.Subs[High(Result.Subs)].Entries,Length(Result.Subs[High(Result.Subs)].Entries)+1);
+                    Result.Subs[High(Result.Subs)].Entries[High(Result.Subs[High(Result.Subs)].Entries)]:=structentry;
+                  END;
+                END ELSE BEGIN
+                  FOR current_package:=0 TO packages-1 DO BEGIN
+                    structentry.offset:=current_base+current_package*current_package_size+HexToLong(fields[1]);
+                    WITH Result.Subs[High(Result.Subs)-packages+current_package+1] DO BEGIN
+                      SetLength(Entries,Length(Entries)+1);
+                      Entries[High(Entries)]:=structentry;
+                    END;
+                  END;
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      CloseFile(deffile);
+    END;
+  END;
+
+
+BEGIN
+//  InsertRawListHandler('AGDB',True,AGDB);
+  InsertRawListHandler('AKVA',True,AKVA);
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.30a/todo.txt
===================================================================
--- /oup/releases/0.30a/todo.txt	(revision 8)
+++ /oup/releases/0.30a/todo.txt	(revision 8)
@@ -0,0 +1,158 @@
+Unit10 unabhängig, funktionsweise wiederherstellen
+Schreibt auch die dat_files[] etc
+Benutzt die *globalen* dat_stream/raw_stream und keine MemCopy
+
+
+
+-Datei von einem Tool in andrem Tool öffnen
+
+-TXMPReplace: Zugriff über Unit2
+
+
+-SELECT [src_id],MIN(datfiles.[name]),SUM(rawmap.[size]) FROM rawmap INNER  JOIN datfiles ON datfiles.[id]=[src_id] GROUP BY [src_id] ORDER BY [src_id] ASC
+
+-Extrahier-Ordner-Option (mit Platzhalter für .dat-Name)
+
+-HELP.hlp
+-About
+
+-BinEdit: Zusatzfunktionen wie: Suche, 
+-BinEdit: Bild/Menu/Button irgendwas zum speichern
+
+-Extractor: Wohin?
+
+-FileCompare: Ergebnis=Tabelle, jede Zeile eine differenz-addresse, spalten = werte an addr. für compared files
+
+-TXMP-Replace: MultiReplace
+
+-Move-Freischalter (Mindestlvl eingabe)
+
+-Löschen einer Datei auf die gelinkt wird: Liste der Links und sicherheitsfrage
+
+-Filebox-Context: Extract etc
+
+-DAT geladen -> Meldung oder sogar "what to do next?"
+-SSG: Levels extrahieren?
+-Pierre: Wie Char-Anims, Char-Models, Levels extrahieren?
+-Language-Files?
+-STRG+C auf Dateilisten etc für kopieren des Namens
+
+-REPACKING: testen lvl0: 690-collisions.txmp einbauen, script: collisions-zeug
+
+#################################################################
+##########                 File-Types                  ##########
+#################################################################
+(3CLA)
+ABNA
+AGDB
+AGQC
+AGQG
+(AGQM)
+AGQR
+AISA
+AITR
+(AIWA)
+AKAA
+AKBA
+AKBP
+AKDA
+AKEV
+AKOT
+AKVA
+BINA
+CBPI
+CBPM
+CONS
+CRSA
+DOOR
+DPge
+(EDIA)
+ENVP
+FILM
+(FXLR)
+(GMAN)
+HPge
+IDXA
+IGHH
+IGPA
+IGPG
+IGSA
+IGSt
+Impt
+IPge
+KeyI
+M3GA
+M3GM
+(M3TA)
+Mtrl
+(NMSA)
+OBAN
+OBDC
+(OBLS)
+OBOA
+OFGA
+ONCC
+ONCP
+ONCV
+ONFA
+ONGS
+ONIA
+ONLD
+ONLV
+ONMA
+ONOA
+ONSA
+ONSK
+ONTA
+ONVL
+ONWC
+OPge
+OSBD
+OTIT
+OTLF
+PLEA
+PNTA
+PSpc
+PSpL
+PSUI
+QTNA
+(QUDA)
+SNDD
+StNA
+SUBT
+(TMFA)
+(TMRA)
+TRAC
+TRAM
+TRAS
+TRBS
+TRCM
+(TRFT)
+TRGA
+TRGE
+TRIA
+TRIG
+TRMA
+TRSC
+TRTA
+TSFF
+TSFL
+TSFT
+TSGA
+TStr
+TURR
+TXAN
+TXCA
+TXMA
+TXMB
+TXMP
+(TXPC)
+TxtC
+(UUEA)
+(UVDL)
+VCRA
+WMCL
+WMDD
+WMM_
+WMMB
+WPge
Index: /oup/releases/0.31a/StructDefs/AISA.txt
===================================================================
--- /oup/releases/0.31a/StructDefs/AISA.txt	(revision 8)
+++ /oup/releases/0.31a/StructDefs/AISA.txt	(revision 8)
@@ -0,0 +1,10 @@
+AI Character Setup Array
+
+File ID	$00	12
+Level ID	$04	4
+Unused	$08	1022
+Packages	$1E	2
+
+*AIs		$20	$1E	2	352
+ONCC-Linkk	$28	12
+Intro func	$50	10032
Index: /oup/releases/0.31a/StructDefs/DOOR.txt
===================================================================
--- /oup/releases/0.31a/StructDefs/DOOR.txt	(revision 8)
+++ /oup/releases/0.31a/StructDefs/DOOR.txt	(revision 8)
@@ -0,0 +1,2 @@
+DOOR File
+Open sound	$24	132	Test
Index: /oup/releases/0.31a/StructDefs/ONCC.txt
===================================================================
--- /oup/releases/0.31a/StructDefs/ONCC.txt	(revision 8)
+++ /oup/releases/0.31a/StructDefs/ONCC.txt	(revision 8)
@@ -0,0 +1,58 @@
+Oni character class
+TXMP link	$28	12	Shadow texture
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use an hypo
+Hurt light sound	$98	10032	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	10032	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	10032	Reference to an OSBD file of level 0
+Death sound	$F8	10032	Reference to an OSBD file of level 0
+Taunt sound query	$2B0	10	00 = not used; 64 = used
+"Whos there?" sound query	$2B1	10	00 = not used; 64 = used
+"I see you" sound query	$2B2	10	00 = not used; 64 = used
+"You lose" sound query	$2B3	10	00 = not used; 64 = used
+"Where are you?" sound query	$2B4	10	00 = not used; 64 = used
+"Why is this happenung?" sound query	$2B5	10	00 = not used; 64 = used
+Superpunch sound query	$2B6	10	00 = not used; 64 = used
+Superkick sound query	$2B7	10	00 = not used; 64 = used
+Super3 sound query	$2B8	10	00 = not used; 64 = used
+Super4 sound query	$2B9	10	00 = not used; 64 = used
+Taunt sound	$2BC	10032	Reference to a SNDD file of level 0
+"Whos there?" sound	$2DC	10032	Reference to a SNDD file of level 0
+"I see you" sound	$2FC	10032	Reference to a SNDD file of level 0
+"You lose" sound	$31C	10032	Reference to a SNDD file of level 0
+"Where are you?" sound	$33C	10032	Reference to a SNDD file of level 0
+"Why is this happenung?" sound	$35C	10032	Reference to a SNDD file of level 0
+Superpunch sound	$37C	10032	Reference to a SNDD file of level 0
+Superkick sound	$39C	10032	Reference to a SNDD file of level 0
+Super3 sound	$3BC	10032	Reference to a SNDD file of level 0
+Super4 sound	$3DC	10032	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV link	$434	12	Character varient link
+ONCP link	$438	12	Character particle array link; useless?
+ONIA link	$43C	12	Character impact array link; useless?
+Unknown	$444	10016	Maybe the weight of the character?
+Footstep walk impact	$454	10128	Reference to the a Impt file of level 0
+Footstep run impact	$4D6	10128	Reference to the a Impt file of level 0
+Footstep crouch impact	$558	10128	Reference to the a Impt file of level 0
+Fall slide impact	$5DA	10128	Reference to the a Impt file of level 0
+Fall land impact	$65C	10128	Reference to the a Impt file of level 0
+Fall land hard impact	$6DE	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$760	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$7E2	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$864	10128	Reference to the a Impt file of level 0
+Footstep turn impact	$8E6	10128	Reference to the a Impt file of level 0
+Footstep run start impact	$968	10128	Reference to the a Impt file of level 0
+Footstep single step impact	$9EA	10128	Reference to the a Impt file of level 0
+Footstep run stop impact	$A6C	10128	Reference to the a Impt file of level 0
+Footstep walk stop impact	$AEE	10128	Reference to the a Impt file of level 0
+Footstep run sprint impact	$B70	10128	Reference to the a Impt file of level 0
+Unknown	$BF4	10064	special death particles; only the mad bomber use it
+TRBS link	$C3C	8	Body set link
+TRMA link	$C40	8	Texture map array link
+CBPM link	$C44	8	Body part material link
+CBPI link	$C48	8	Body part impact link
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC link	$C88	8	Animation collection link
+TRSC link	$C8C	8	Screen (aiming) collection link
Index: /oup/releases/0.31a/StructDefs/SUBT.txt
===================================================================
--- /oup/releases/0.31a/StructDefs/SUBT.txt	(revision 8)
+++ /oup/releases/0.31a/StructDefs/SUBT.txt	(revision 8)
@@ -0,0 +1,5 @@
+Subtitles
+ID	$00	4	ID of this file
+LevelID	$04	8	ID of the level this file is in
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Subtitle count	$1C	4	Number of subtitles in this file
Index: /oup/releases/0.31a/StructDefs/TRAM.txt
===================================================================
--- /oup/releases/0.31a/StructDefs/TRAM.txt	(revision 8)
+++ /oup/releases/0.31a/StructDefs/TRAM.txt	(revision 8)
@@ -0,0 +1,49 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	8	Flags; It seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	8	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	8	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	2	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	116	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	6	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
Index: /oup/releases/0.31a/StructDefs/TXAN.txt
===================================================================
--- /oup/releases/0.31a/StructDefs/TXAN.txt	(revision 8)
+++ /oup/releases/0.31a/StructDefs/TXAN.txt	(revision 8)
@@ -0,0 +1,14 @@
+Texture Animation
+
+File ID	$00	12	File ID of this file
+Level Number	$04	4
+Unused	$08	1012
+
+Loop speed	$14	2
+Unknown	$16	2
+Unknown	$18	2
+Unused	$1A	1002
+Number of images	$1C	4
+
+*Packages		$20	$1C	4	4
+Image	$0	12
Index: /oup/releases/0.31a/StructDefs/TXMP.txt
===================================================================
--- /oup/releases/0.31a/StructDefs/TXMP.txt	(revision 8)
+++ /oup/releases/0.31a/StructDefs/TXMP.txt	(revision 8)
@@ -0,0 +1,13 @@
+Texture
+ID	$00	12	ID of this file
+LevelID	$04	8	ID of the level this file is in
+FileName	$08	10128	
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	12	Link to the TXAN-file (if this TXMP is the first image of an animation)
+TXMP-Link	$98	12	Link to another TXMP-file
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
Index: /oup/releases/0.31a/blubb.txt
===================================================================
--- /oup/releases/0.31a/blubb.txt	(revision 8)
+++ /oup/releases/0.31a/blubb.txt	(revision 8)
@@ -0,0 +1,6 @@
+___FILEINDEX___.txt
+
+
+TXMP:
+MipMapping: Bit0=an/aus
+ColorDepth: Bit0=??AnimationPic??, Bit1=shade vertex, Bit2=transparency, Bit4=16bit, Bit5=32bit
Index: /oup/releases/0.31a/changelog.txt
===================================================================
--- /oup/releases/0.31a/changelog.txt	(revision 8)
+++ /oup/releases/0.31a/changelog.txt	(revision 8)
@@ -0,0 +1,103 @@
+OniUnPacker v0.31a
+------------------
++Dat2DB function working
++Fixed a bug which appeared when multiple windows of the same class were opened at one time (eg 2*BinEdit)
+
+OniUnPacker v0.30a
+------------------
++Completely rewritten data-backend-connection-classes (Unit15_Classes.pas)
+
+OniUnPacker v0.29a
+------------------
++Little changes in StructureDefs
+
+OniUnPacker v0.29a
+------------------
++New StructureViewer
++New StructureTypes: 12=.dat-file-ID, 13..16=SignedInteger, 1000..9999=Unused data
++Dynamic Structures (look at TXAN-files or AISA-files for examples)
++File-type associations (.dat, .oldb, .opf) with OUP possible
++File IDs as Hex
+
+OniUnPacker v0.28a
+------------------
++StructureDefinitions as separate txt-files
++Minor bugfixes
++Ctrl+C for Hex-fields
+
+OniUnPacker v0.27a
+------------------
++Added MAC-file support
++Added StructureDefs for ONCCs / TRAMs (thanks to SSG)
+
+OniUnPacker v0.26a
+------------------
++Fixed some bugs again ;)
+
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.31a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.31a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.31a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,183 @@
+﻿<?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 Name="UnitInitSeq">True</Compiler>
+			<Compiler Name="LocalPInvoke">True</Compiler>
+			<Compiler Name="CodePage"></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 Name="GenerateHpps">False</Linker>
+		</Linker>
+		<Directories>
+			<Directories Name="OutputDir">exe</Directories>
+			<Directories Name="UnitOutputDir">dcu</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 Name="Debug Symbols Search Path"></Parameters>
+			<Parameters Name="LoadAllSymbols">True</Parameters>
+			<Parameters Name="LoadUnspecifiedSymbols">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>
+		<Language>
+			<Language Name="ActiveLang"></Language>
+			<Language Name="ProjectLang">$00000000</Language>
+			<Language Name="RootDir"></Language>
+		</Language>  <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.31a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.31a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.31a/src/OniUnPacker.cfg	(revision 8)
@@ -0,0 +1,40 @@
+-$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
+-E"exe"
+-N0"dcu"
+-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.31a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.31a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.31a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,32 @@
+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},
+  Unit13_rawedit in 'Unit13_rawedit.pas' {Form13},
+  Unit14_settings in 'Unit14_settings.pas' {Form14},
+  ftypesAPI in 'TFileTypeRegistration\ftypesAPI.pas',
+  Unit15_Classes in 'Unit15_Classes.pas';
+
+{$R *.res}
+{$R icon2.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.CreateForm(TForm12, Form12);
+  Application.CreateForm(TForm14, Form14);
+  Application.Run;
+END.
Index: /oup/releases/0.31a/src/TFileTypeRegistration/IsAdmin.inc
===================================================================
--- /oup/releases/0.31a/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
+++ /oup/releases/0.31a/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
@@ -0,0 +1,90 @@
+function GetAdminSid: PSID;
+const
+  // bekannte SIDs ... (WinNT.h)
+  SECURITYNTAUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
+  // bekannte RIDs ... (WinNT.h)
+  SECURITYBUILTINDOMAINRID: DWORD = $00000020;
+  DOMAINALIASRIDADMINS: DWORD = $00000220;
+begin
+  Result := nil;
+  AllocateAndInitializeSid(SECURITYNTAUTHORITY,
+    2,
+    SECURITYBUILTINDOMAINRID,
+    DOMAINALIASRIDADMINS,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    Result);
+end;
+
+function IsAdmin: LongBool;
+var
+  TokenHandle      : THandle;
+  ReturnLength     : DWORD;
+  TokenInformation : PTokenGroups;
+  AdminSid         : PSID;
+  Loop             : Integer;
+  wv               : TOSVersionInfo;
+begin
+  wv.dwOSVersionInfoSize := sizeof(TOSversionInfo);
+  GetVersionEx(wv);
+
+  Result := (wv.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS);
+
+  if(wv.dwPlatformId = VER_PLATFORM_WIN32_NT) then
+    begin
+      TokenHandle := 0;
+      if OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, TokenHandle) then
+        try
+          ReturnLength := 0;
+          GetTokenInformation(TokenHandle, TokenGroups, nil, 0, ReturnLength);
+          TokenInformation := GetMemory(ReturnLength);
+          if Assigned(TokenInformation) then
+            try
+              if GetTokenInformation(TokenHandle, TokenGroups,
+                TokenInformation, ReturnLength, ReturnLength) then
+              begin
+                AdminSid := GetAdminSid;
+                for Loop := 0 to TokenInformation^.GroupCount - 1 do
+                  begin
+                    if EqualSid(TokenInformation^.Groups[Loop].Sid, AdminSid) then
+                      begin
+                        Result := True; break;
+                      end;
+                  end;
+                FreeSid(AdminSid);
+              end;
+            finally
+              FreeMemory(TokenInformation);
+            end;
+        finally
+          CloseHandle(TokenHandle);
+        end;
+    end;
+end;
+
+function WVersion: string; 
+var 
+  OSInfo: TOSVersionInfo; 
+begin 
+  Result := '3X'; 
+  OSInfo.dwOSVersionInfoSize := sizeof(TOSVERSIONINFO); 
+  GetVersionEx(OSInfo); 
+  case OSInfo.dwPlatformID of 
+    VER_PLATFORM_WIN32S: begin 
+        Result := '3X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_WINDOWS: begin 
+        Result := '9X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_NT: begin 
+        Result := 'NT'; 
+        Exit; 
+      end; 
+  end; //case 
+end;
Index: /oup/releases/0.31a/src/TFileTypeRegistration/SysUtils.inc
===================================================================
--- /oup/releases/0.31a/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
+++ /oup/releases/0.31a/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
@@ -0,0 +1,307 @@
+function fileexists(const szFilename: string): boolean;
+var
+  Handle   : THandle;
+  FindData : TWin32FindData;
+begin
+  Handle := FindFirstFile(pchar(szFilename),FindData);
+  Result := (Handle <> INVALID_HANDLE_VALUE);
+
+  if(Result) then Windows.FindClose(Handle);
+end;
+
+function ExtractFileDrive(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') then
+    begin
+      Result := copy(szFilename,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFilePath(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFileName);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') or
+      (szFileName[i] = '\') then
+    begin
+      Result := copy(szFileName,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFileName(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '\') then
+      break;
+
+    dec(i);
+  end;
+
+  Result := copy(szFilename,i + 1,length(szFilename));
+end;
+
+function CutFileExt(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '.') then
+      break;
+
+    dec(i);
+  end;
+
+  if(i = 0) then Result := szFilename
+    else Result := copy(szFilename,1,i-1);
+end;
+
+function ChangeFileExt(const szFileName, szNewExt: string): string;
+begin
+  Result := CutFileExt(szFileName);
+
+  if(szNewExt[1] <> '.') then Result := Result + '.' + szNewExt
+    else Result := Result + szNewExt;
+end;
+
+function FileSearch(const Name, DirList: string): string;
+var
+  I, P, L: Integer;
+begin
+  Result := Name;
+  P      := 1;
+  L      := length(DirList);
+
+  while(true) do begin
+    if(fileexists(Result)) then exit;
+
+    while(P <= L) and (DirList[P] = ';') do inc(P);
+    if(P > L) then break;
+
+    I := P;
+    while(P <= L) and (DirList[P] <> ';') do inc(P);
+
+    Result   := copy(DirList,I,P-I);
+    if not(Result[length(Result)] in[':','\']) then
+      Result := Result + '\';
+
+    Result := Result + Name;
+  end;
+
+  Result  := '';
+end;
+
+function StrToIntDef(const s: string; const i: integer): integer;
+var
+  code : integer;
+begin
+  Val(s,Result,code); if(code <> 0) then
+                        Result := i;
+end;
+
+function IntToStr(const i: integer): string;
+begin
+  Str(i,Result);
+end;
+
+// -----------------------------------------------------------------------------
+
+function Format(fmt: string; params: array of const): string;
+var
+  pdw1,
+  pdw2 : PDWORD;
+  i    : integer;
+  pc   : PCHAR;
+begin
+  pdw1 := nil;
+
+  if High(params) >= 0 then
+    GetMem(pdw1, (High(params) + 1) * sizeof(Pointer));
+
+  pdw2  := pdw1;
+  for i := 0 to High(params) do
+    begin
+      pdw2^ := PDWORD(@params[i])^;
+      inc(pdw2);
+    end;
+
+  pc := GetMemory(1024);
+  if Assigned(pc) then
+    try
+      SetString(Result, pc, wvsprintf(pc, PCHAR(fmt), PCHAR(pdw1)));
+    finally
+      if (pdw1 <> nil) then FreeMem(pdw1);
+      FreeMem(pc);
+    end
+  else
+    Result := '';
+end;
+
+
+// -----------------------------------------------------------------------------
+
+function UpperCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        Result[i] := UpCase(s[i]);
+    end;
+end;
+
+function LowerCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        case s[i] of
+          'A'..'Z','Ä','Ö','Ü':
+            Result[i] := CHR(BYTE(s[i]) + 32);
+          else
+            Result[i] := s[i];
+        end;
+    end;
+end;
+
+function LoggedUser: string;
+var
+  dwLen  : dword;
+  fTest  : boolean;
+begin
+  Result := '';
+  dwLen  := MAX_PATH; SetLength(Result,dwLen);
+
+  fTest  := GetUserName(@Result[1],dwLen);
+
+  if(not fTest) and (GetLastError = ERROR_MORE_DATA) then begin
+    SetLength(Result,dwLen);
+    fTest := GetUserName(@Result[1],dwLen);
+  end;
+
+  if(fTest) and (Result[1] <> #0) then
+    SetLength(Result,dwLen - 1);
+end;
+
+// -----------------------------------------------------------------------------
+
+//
+// delete files during next reboot (code by sakura)
+//
+function DeleteFileDuringNextSystemBoot(aFileName: string): Boolean;
+var
+  ShortName,
+  winini    : string;
+  os        : TOSVersionInfo;
+  ts        : array of string;
+  f         : TextFile;
+  i         : integer;
+begin
+  Result := False;
+
+  // get OS version
+  os.dwOSVersionInfoSize := sizeof(TOSVersionInfo);
+  GetVersionEx(os);
+
+  case os.dwPlatformId of
+    // NT systems
+    VER_PLATFORM_WIN32_NT:
+      Result := MoveFileEx(pchar(aFileName),nil,
+        MOVEFILE_REPLACE_EXISTING + MOVEFILE_DELAY_UNTIL_REBOOT);
+    // 9x systems
+    VER_PLATFORM_WIN32_WINDOWS:
+      begin
+        // get Windows folder
+        SetLength(winini,MAX_PATH+1);
+        SetLength(winini,GetWindowsDirectory(@winini[1],MAX_PATH+1));
+
+        if(winini <> '') then begin
+          if(winini[length(winini)] <> '\') then
+            winini := winini + '\';
+          winini   := winini + 'wininit.ini';
+
+          // get short name of the given file
+          SetLength(ShortName,MAX_PATH+1);
+          SetLength(ShortName,
+            GetShortPathName(@aFilename[1],@ShortName[1],MAX_PATH+1));
+
+          if(ShortName <> '') then begin
+            // add it to "wininit.ini" to delete
+            // during next reboot
+            SetLength(ts,0);
+
+            {$I-}
+            // get old file´s content
+            AssignFile(f,winini);
+            ReSet(f);
+            if(IoResult = 0) then begin
+              while(not eof(f)) do begin
+                SetLength(ts,length(ts)+1);
+                ReadLn(f,ts[length(ts)-1]);
+
+                if(lstrcmpi('[rename]',pchar(ts[length(ts)-1])) = 0) then begin
+                  SetLength(ts,length(ts)+1);
+                  ts[length(ts)-1] := 'NUL='+ShortName;
+                end;
+              end;
+              CloseFile(f);
+            end;
+
+            if(length(ts) = 0) then begin
+              SetLength(ts,2);
+              ts[0] := '[rename]';
+              ts[1] := 'NUL='+ShortName;
+            end;
+
+            // re-create
+            ReWrite(f);
+            Result := (IoResult = 0);
+            if(Result) then begin
+              for i := 0 to length(ts) - 1 do
+                WriteLn(f,ts[i]);
+
+              CloseFile(f);
+            end;
+            {$I+}
+
+            SetLength(ts,0);
+          end;
+        end;
+      end;
+    // only 9x and NT are supported
+    else
+      exit;
+  end;
+end;
Index: /oup/releases/0.31a/src/TFileTypeRegistration/demo.txt
===================================================================
--- /oup/releases/0.31a/src/TFileTypeRegistration/demo.txt	(revision 8)
+++ /oup/releases/0.31a/src/TFileTypeRegistration/demo.txt	(revision 8)
@@ -0,0 +1,34 @@
+uses
+  ftypesAPI;
+
+var
+  ftr    : TFileTypeRegistration;
+  s:String;
+
+
+ftr := TFileTypeRegistration.Create;
+if(ftr <> nil) then begin
+  try
+    if(LOWORD(wp) = IDC_CREATEFOO) then begin
+      if(ftr.RegisterType('.foo','FooFile','FOO-File')) then begin
+        ftr.AddHandler('open','notepad.exe "%1"','Öffnen');
+        ftr.AddHandler('print','notepad.exe /p "%1"');
+        ftr.SetDefaultHandler;
+        ftr.AddNewFileSupport('.foo');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_DELPRINTVERB) then begin
+      if(ftr.GetInternalKey('.foo') <> '') then begin
+        ftr.DeleteHandler('print');
+        ftr.SetDefaultHandler('open');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_REMOVEFOO) then begin
+      s := ftr.GetInternalKey('.foo');
+      if(MessageBox(hwndDlg,pchar('Wollen Sie wirklich ".foo" und "' + s + '" entfernen?'), 'Frage',MB_YESNO or MB_DEFBUTTON2 or MB_ICONQUESTION) = ID_YES) then
+        ftr.UnregisterType('.foo');
+    end;
+  finally
+    ftr.Free;
+  end;
+end;
Index: /oup/releases/0.31a/src/TFileTypeRegistration/ftypesAPI.pas
===================================================================
--- /oup/releases/0.31a/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
+++ /oup/releases/0.31a/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
@@ -0,0 +1,544 @@
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse (Win32-API)
+// Copyright (c) 2004 Mathias Simmack
+//
+// -----------------------------------------------------------------------------
+
+// -- Revision history ---------------------------------------------------------
+//
+//   * erste Version
+//
+// -----------------------------------------------------------------------------
+unit ftypesAPI;
+
+interface
+
+uses
+  Windows, ShlObj;
+
+type
+  TFileTypeRegistration = class
+    FRegConnector : HKEY;
+    FExtension,
+    FInternalName : string;
+    FVerb         : string;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function RegisterType(const Extension, InternalName: string;
+      Description: string = ''; IconFile: string = '';
+      IconIndex: integer = -1): boolean;
+    function UnregisterExtension(const Extension: string): boolean;
+    function UnregisterType(const Extension: string): boolean;
+    procedure UpdateShell;
+    function AddHandler(const HandlerVerb, CommandLine: string;
+      HandlerDescription: string = ''): boolean; overload;
+    function DeleteHandler(const HandlerVerb: string): boolean;
+    function SetDefaultHandler: boolean; overload;
+    function SetDefaultHandler(const HandlerVerb: string): boolean; overload;
+    function GetInternalKey(const Extension: string): string;
+    function AddNewFileSupport(const Extension: string): boolean;
+    function RemoveNewFileSupport(const Extension: string): boolean;
+
+    property Extension: string read FExtension;
+    property InternalName: string read FInternalName;
+    property CurrentVerb: string read FVerb;
+  end;
+
+
+implementation
+
+(* *****************************************************************************
+
+  Beispiel #1: Einen neuen Dateityp registrieren
+  ----------------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // die Dateiendung ".foo" registrieren, der interne Schlüssel
+    // lautet "FooFile", eine Beschreibung und eine Symboldatei
+    // sind ebenfalls angegeben
+    if(ftr.RegisterType('.foo','FooFile','FOO Description',
+      'c:\folder\icon.ico')) then
+    begin
+      // fügt den Handler "open" hinzu und verknüpft ihn mit dem
+      // Programm "foo.exe"
+      ftr.AddHandler('open','"c:\folder\foo.exe" "%1"');
+
+      // setzt den zuletzt benutzten Handler ("open" in dem Fall)
+      // als Standard
+      ftr.SetDefaultHandler;
+    end;
+
+    if(ftr.RegisterType('.foo','ThisIsNotTheFOOKey')) then
+    // Das ist kein Fehler! Obwohl hier der interne Name
+    // "ThisIsNotTheFOOKey" verwendet wird, benutzt die Funktion
+    // intern den bereits vorhandenen Schlüssel "FooFile" (s. oben).
+    begin
+      // zwei neue Handler werden registriert, ...
+      ftr.AddHandler('print','"c:\folder\foo.exe" /p "%1"');
+      ftr.AddHandler('edit','notepad.exe "%1"');
+
+      // ... & dank der überladenen Funktion "SetDefaultHandler"
+      // kann diesmal auch "print" als Standardhandler gesetzt
+      // werden
+      ftr.SetDefaultHandler('print');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #2: Einen neuen Typ mit einem vorhandenen Schlüssel
+  verknüpfen
+  ------------------------------------------------------------
+
+  Das Beispiel registriert die Endung ".foo" auf die gleiche
+  Weise wie Textdateien (.txt). Es wird einfach der interne
+  Schlüsselname ermittelt und für die Endung ".foo" gesetzt
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    strInternalTextFileKey := ftr.GetInternalKey('.txt');
+    if(strInternalTextFileKey <> '') then
+      ftr.RegisterType('.foo',strInternalTextFileKey);
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #3: Einen Handler entfernen
+  ------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // den internen Schlüsselnamen des Typs ".foo" ermitteln, ...
+    if(ftr.GetInternalKey('.foo') <> '') then
+    // ... wobei das Ergebnis in dem Fall unwichtig ist, weil
+    // intern auch die Eigenschaft "FInternalName" gesetzt
+    // wird
+    begin
+      // den "print"-Handler entfernen, ...
+      ftr.DeleteHandler('print');
+
+      // ... & den Standardhandler aktualisieren
+      ftr.SetDefaultHandler('open');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #4: Nur eine Dateiendung entfernen
+  -------------------------------------------
+
+  In diesem Fall wird lediglich die Endung ".foo" entfernt. Der
+  evtl. vorhandene interne Schlüssel bleibt bestehen. Das ist
+  für das Beispiel #2 nützlich, wenn die Endung ".foo" entfernt
+  werden soll, intern aber mit den Textdateien verlinkt ist, die
+  ja im Normalfall nicht entfernt werden dürfen/sollten.
+
+    ftr.UnregisterExtension('.foo');
+
+
+  Beispiel #5: Den kompletten Dateityp entfernen
+  ----------------------------------------------
+
+  Dieses Beispiel entfernt dagegen den kompletten Dateityp,
+  inkl. des evtl. vorhandenen internen Schlüssels (vgl. mit
+  Beispiel #4).
+
+    ftr.UnregisterType('.foo');
+
+  Bezogen auf Beispiel #2 wäre das die fatale Lösung, weil dadurch
+  zwar die Endung ".foo" deregistriert wird, gleichzeitig wird
+  aber auch der intern verwendete Schlüssel der Textdateien
+  gelöscht.
+
+  ALSO, VORSICHT!!!
+
+***************************************************************************** *)
+
+
+//
+// Admin-Rechte sind erforderlich (Funktion von NicoDE)
+//
+{$INCLUDE IsAdmin.inc}
+{$INCLUDE SysUtils.inc}
+
+
+// -----------------------------------------------------------------------------
+//
+// Registry
+//
+// -----------------------------------------------------------------------------
+
+function RegWriteSubKeyVal(const parent: HKEY; SubKeyName: string;
+  ValueName, Value: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := false;
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegCreateKeyEx(parent,pchar(SubKeyName),0,nil,0,KEY_READ or KEY_WRITE,
+    nil,tmp,nil) = ERROR_SUCCESS) then
+  try
+    Result := (RegSetValueEx(tmp,pchar(ValueName),0,REG_SZ,pchar(Value),
+      length(Value) + 1) = ERROR_SUCCESS);
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegReadSubKeyStr(const parent: HKEY; SubKeyName: string;
+  ValueName: string): string;
+var
+  tmp     : HKEY;
+  lpData,
+  dwLen   : dword;
+begin
+  Result  := '';
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegOpenKeyEx(parent,pchar(SubKeyName),0,KEY_READ,
+    tmp) = ERROR_SUCCESS) then
+  try
+    lpData := REG_NONE;
+    dwLen  := 0;
+    if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,nil,
+         @dwLen) = ERROR_SUCCESS) and
+      (lpData in[REG_SZ,REG_EXPAND_SZ]) and
+      (dwLen > 0) then
+    begin
+      SetLength(Result,dwLen);
+
+      if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,
+           @Result[1],@dwLen) = ERROR_SUCCESS) then
+        SetLength(Result,dwLen - 1)
+      else
+        Result := '';
+    end;
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegKeyExists(const parent: HKEY; KeyName: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := (RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,tmp) =
+    ERROR_SUCCESS);
+  if(Result) then RegCloseKey(tmp);
+end;
+
+function RegDeleteWholeKey(parent: HKEY; KeyName: string): boolean;
+var
+  reg       : HKEY;
+  dwSubkeys : dword;
+  dwLen     : dword;
+  i         : integer;
+  buf       : array[0..MAX_PATH]of char;
+begin
+  if(RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,reg) = ERROR_SUCCESS) then
+  try
+    if(RegQueryInfoKey(reg,nil,nil,nil,@dwSubKeys,nil,
+      nil,nil,nil,nil,nil,nil) = ERROR_SUCCESS) and
+      (dwSubKeys > 0) then
+    for i := 0 to dwSubKeys - 1 do begin
+      ZeroMemory(@buf,sizeof(buf));
+      dwLen   := MAX_PATH;
+
+      if(RegEnumKeyEx(reg,i,buf,dwLen,nil,nil,nil,nil) = ERROR_SUCCESS) and
+        (dwLen > 0) then
+      RegDeleteWholeKey(reg,buf);
+    end;
+  finally
+    RegCloseKey(reg);
+  end;
+
+  Result := (RegDeleteKey(parent,pchar(KeyName)) = ERROR_SUCCESS);
+end;
+
+
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse
+//
+// -----------------------------------------------------------------------------
+
+constructor TFileTypeRegistration.Create;
+var
+  key: HKEY;
+  sub: PChar;
+begin
+  FExtension    := '';
+  FInternalName := '';
+  FVerb         := '';
+
+  // Zugriff auf die Registry, & HKEY_CLASSES_ROOT
+  // als Root setzen
+  if(WVersion='9X') or IsAdmin then begin
+    key:=HKEY_CLASSES_ROOT;
+    sub:=nil;
+  end else begin
+    key:=HKEY_CURRENT_USER;
+    sub:=PChar('SOFTWARE\Classes');
+  end;
+
+  if RegOpenKeyEx(key,sub,0,KEY_ALL_ACCESS, FRegConnector) <> ERROR_SUCCESS then
+    FRegConnector := INVALID_HANDLE_VALUE;
+end;
+
+destructor TFileTypeRegistration.Destroy;
+begin
+  if(FRegConnector <> INVALID_HANDLE_VALUE) then
+    RegCloseKey(FRegConnector);
+end;
+
+function TFileTypeRegistration.RegisterType(const Extension,
+  InternalName: string; Description: string = ''; IconFile: string = '';
+  IconIndex: integer = -1): boolean;
+var
+  strDummy : string;
+begin
+  // Standardergebnis
+  Result         := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // ist dieser Typ evtl. schon registriert?
+  strDummy := self.GetInternalKey(Extension);
+
+  // Nein. :o)
+  if(strDummy = '') then strDummy := InternalName;
+
+  // den Schlüssel mit der Dateiendung anlegen oder aktualisieren
+  Result := RegWriteSubKeyVal(FRegConnector,Extension,'',strDummy);
+  if(not Result) then exit;
+
+  // den internen Schlüssel öffnen
+  if(Result) then
+  begin
+    // Beschreibung anlegen
+    if(Description <> '') then
+      RegWriteSubKeyVal(FRegConnector,strDummy,'',Description);
+
+    // Symbol zuweisen (Datei muss existieren!)
+    if(IconFile <> '') and
+      (fileexists(IconFile)) then
+    begin
+      if(IconIndex <> -1) then
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',Format('%s,%d',[IconFile,IconIndex]))
+      else
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',IconFile);
+    end;
+  end;
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+
+  // Properties aktualisieren
+  if(Result) then
+  begin
+    FExtension    := Extension;
+    FInternalName := strDummy;
+  end;
+end;
+
+function TFileTypeRegistration.UnregisterExtension(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // die Endung entfernen
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegDeleteWholeKey(FRegConnector,Extension));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+function TFileTypeRegistration.UnregisterType(const Extension: string):
+  boolean;
+var
+  strDummy : string;
+begin
+  Result   := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // den internen Namen der Endung ermitteln
+  strDummy := self.GetInternalKey(Extension);
+
+  // die Endung entfernen (s. "UnregisterExtension"), ...
+  Result   := (self.UnregisterExtension(Extension)) and
+  // ... & den internen Schlüssel löschen
+    (strDummy <> '') and
+    (RegKeyExists(FRegConnector,strDummy)) and
+    (RegDeleteWholeKey(FRegConnector,strDummy));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+procedure TFileTypeRegistration.UpdateShell;
+begin
+  SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,nil,nil);
+end;
+
+
+const
+  ShellKey = '%s\shell\%s';
+
+function TFileTypeRegistration.AddHandler(const HandlerVerb,
+  CommandLine: string; HandlerDescription: string = ''): boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') or
+    (CommandLine = '') then exit;
+
+  // der interne Schlüssel muss existieren
+  if(RegKeyExists(FRegConnector,FInternalName)) then
+  begin
+    // den Handler (= Verb) erzeugen
+    Result := RegWriteSubKeyVal(FRegConnector,
+      Format(ShellKey + '\command',[FInternalName,HandlerVerb]),
+      '',
+      CommandLine);
+
+    // ggf. Beschreibung für Handler setzen
+    if(HandlerDescription <> '') then
+      RegWriteSubKeyVal(FRegConnector,
+        Format(ShellKey,[FInternalName,HandlerVerb]),
+        '',
+        HandlerDescription);
+  end;
+
+  // interne Eigenschaft anpassen (für "SetDefaultHandler")
+  if(Result) then
+    FVerb := HandlerVerb;
+end;
+
+function TFileTypeRegistration.DeleteHandler(const HandlerVerb: string):
+  boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // Handlerschlüssel entfernen (sofern vorhanden)
+  Result :=
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) and
+    (RegDeleteWholeKey(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb])));
+end;
+
+function TFileTypeRegistration.SetDefaultHandler: boolean;
+begin
+  if(FInternalName <> '') and (FVerb <> '') then
+    Result := self.SetDefaultHandler(FVerb)
+  else
+    Result := false;
+end;
+
+function TFileTypeRegistration.SetDefaultHandler(const HandlerVerb: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // interner Schlüssel muss existieren, ...
+  if(RegKeyExists(FRegConnector,FInternalName)) and
+  // ... & Handler muss existieren, ...
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) then
+  begin
+  // ... dann den Handler als Standard eintragen
+    Result := RegWriteSubKeyVal(FRegConnector,FInternalName + '\shell',
+      '',HandlerVerb);
+  end;
+end;
+
+function TFileTypeRegistration.GetInternalKey(const Extension: string): string;
+begin
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // einen evtl. eingestellten internen Namen zurücksetzen
+  FInternalName   := '';
+
+  // den Schlüssel der Dateiendung öffnen, ...
+  if(RegKeyExists(FRegConnector,Extension)) then
+    FInternalName := RegReadSubKeyStr(FRegConnector,Extension,'');
+
+  // ... als Funktionsergebnis zurückliefern
+  if(not RegKeyExists(FRegConnector,FInternalName)) then
+    FInternalName := '';
+
+  Result := FInternalName;
+end;
+
+
+function TFileTypeRegistration.AddNewFileSupport(const Extension: string):
+  boolean;
+var
+  Description : string;
+begin
+  Result      := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // interne Beschreibung des Typs ermitteln
+  if(self.GetInternalKey(Extension) <> '') then
+    Description := RegReadSubKeyStr(FRegConnector,FInternalName,'')
+  else
+    Description := '';
+
+  // die Beschreibung darf keine Leerzeichen enthalten, weil sie
+  // als Referenz für den neuen Dateinamen verwendet wird, ...
+  if(pos(#32,Description) > 0) or
+  // ... & sie darf auch nicht leer sein
+    (Description = '') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegWriteSubKeyVal(FRegConnector,Extension + '\ShellNew','NullFile',''));
+end;
+
+function TFileTypeRegistration.RemoveNewFileSupport(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension + '\ShellNew')) and
+    (RegDeleteWholeKey(FRegConnector,Extension + '\ShellNew'));
+end;
+
+end.
Index: /oup/releases/0.31a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit10_leveldb.dfm	(revision 8)
@@ -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.31a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.31a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,942 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit9_data_structures, Unit15_Classes;
+
+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;
+  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.CreateLevel(source,target:String);
+  VAR
+    i:LongWord;
+  BEGIN
+  END;
+
+PROCEDURE TForm10.CreateDatabase(source,target:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+    extlist:TExtensionsMap;
+    fileinfo:TFileInfo;
+  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
+    IF NOT CreateDataConnection(source,ODB_Dat) THEN BEGIN
+      ShowMessage('Could not connect to .dat-file');
+      Exit;
+    END ELSE BEGIN
+      TOniDataDat(OniDataConnection).UnloadWhenUnused:=False;
+    END;
+
+    Form10.Visible:=True;
+    Form1.Visible:=False;
+    step:=0;
+    converting:=True;
+    abort:=False;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+    loaded_filename:=target;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=target;
+    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(OniDataConnection.LevelInfo.Ident));
+    FOR i:=0 TO High(OniDataConnection.LevelInfo.Ident) DO data[i]:=OniDataConnection.LevelInfo.Ident[i];
+    temps:=CreateHexString(data,True);
+    Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("ident","'+temps+'");';
+    Query.ExecSQL;
+    Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("lvl","'+IntToStr(OniDataConnection.LevelInfo.LevelNumber)+'");';
+    Query.ExecSQL;
+    IF OniDataConnection.OSisMAC THEN
+      Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("os","MAC");'
+    ELSE
+      Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("os","PC");';
+    Query.ExecSQL;
+
+    DoStep('Writing extensionslist');
+    progress.Max:=Length(OniDataConnection.GetExtensionsList);
+    Application.ProcessMessages;
+
+    extlist:=OniDataConnection.GetExtendedExtensionsList;
+    FOR i:=0 TO High(extlist) DO BEGIN
+      SetLength(data,Length(extlist[i].Ident));
+      FOR j:=0 TO High(extlist[i].Ident) DO data[j]:=extlist[i].Ident[j];
+      temps:=CreateHexString(data,True);
+      temps2:=extlist[i].Extension[3]+extlist[i].Extension[2]+extlist[i].Extension[1]+extlist[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(Length(extlist));
+      Application.ProcessMessages;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    lbl_progress.Caption:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(OniDataConnection.GetFilesCount);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    progress.Max:=OniDataConnection.GetFilesCount;
+    begintime:=Time;
+    DoStep('Writing .dat-fileslist');
+    Application.ProcessMessages;
+
+    Database.StartTransaction;
+    FOR i:=0 TO OniDataConnection.GetFilesCount-1 DO BEGIN
+      fileinfo:=OniDataConnection.GetFileInfo(i);
+      IF (fileinfo.FileType AND $02)=0 THEN BEGIN
+        mimecoder:=TStringFormat_MIME64.Create;
+        data:=OniDataConnection.LoadDatFile(i);
+        Query.SQL.Text:='INSERT INTO datfiles (id,extension,name,contenttype,size,data) VALUES ('+IntToStr(i)+',"'+fileinfo.Extension+'","'+fileinfo.Name+'","'+IntToHex(fileinfo.FileType,8)+'",'+IntToStr(fileinfo.Size)+',MimeToBin("'+MimeCoder.StrTo(@data[0], Length(data))+'") );';
+        Query.ExecSQL;
+        mimecoder.Free;
+
+        rawlist:=OniDataConnection.GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              SetLength(data, rawlist[j].raw_size);
+              OniDataConnection.LoadRawFile(i,rawlist[j].src_offset,data);
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(@data[0], rawlist[j].raw_size)+'") );';
+              Query.ExecSQL;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        HandleFile(fileinfo.Extension,i,True);
+      END ELSE BEGIN
+        Query.SQL.Text:='INSERT INTO datfiles (id,extension,name,contenttype,size) VALUES ('+IntToStr(i)+',"'+fileinfo.Extension+'","'+fileinfo.Name+'","'+IntToHex(fileinfo.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*progress.Max+begintime);
+      progress.Position:=i;
+      lbl_progress.Caption:='Files done: '+IntToStr(i)+'/'+IntToStr(progress.Max);
+      Application.ProcessMessages;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    Database.Commit(False);
+    progress.Position:=progress.Max;
+    lbl_progress.Caption:='Files done: '+IntToStr(progress.Max)+'/'+IntToStr(progress.Max);
+    lbl_estimation.Caption:='FINISHED (duration: '+TimeToStr(Time-absolutebegintime)+')';
+
+    DoStep('FIN');
+    btn_abortok.Caption:='&OK';
+    btn_abortok.Default:=True;
+
+    converting:=False;
+
+    database.Close;
+    database.Free;
+
+    CloseDataConnection;
+  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 InsertDatLinkToDB(fileid:LongWord; offset:LongWord);
+  VAR
+    link:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(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 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 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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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 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
+      OniDataConnection.LoadDatFilePart(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 STNA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:Word;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(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);
+      OniDataConnection.LoadDatFilePart(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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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
+      OniDataConnection.LoadDatFilePart(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',False,NIL);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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.31a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+object Form11: TForm11
+  Left = 0
+  Top = 0
+  Caption = 'Extractor'
+  ClientHeight = 398
+  ClientWidth = 487
+  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 = 0
+        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
+      MultiSelect = True
+      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.31a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.31a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit11_extractor.pas	(revision 8)
@@ -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, Unit15_Classes;
+
+
+PROCEDURE TForm11.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+            END ELSE BEGIN
+              ExportFile(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]),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(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+          END ELSE BEGIN
+            ExportFile(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]),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.31a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.31a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.31a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,119 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      13..16: BEGIN
+              Exit;
+              edit_new.EditType:=etInteger;
+              edit_new.LimitCheck:=True;
+              edit_new.Max:=Int((Power(256,datatype-13)) / 2)-1;
+              edit_new.Min:=1-Int((Power(256,datatype-13)) / 2)-1;
+            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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.31a/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,324 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  ClientHeight = 640
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    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 = 592
+      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 = []
+      OnKeyUp = hexKeyUp
+      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 = 600
+      Width = 483
+      Height = 40
+      Align = alBottom
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      Enabled = False
+      FixedCols = 0
+      RowCount = 1
+      FixedRows = 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 = 374
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      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 = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 337
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 352
+        Width = 146
+        Height = 88
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        OnResize = panel_extensionResize
+        object lbl_filter: TLabel
+          Left = 2
+          Top = 46
+          Width = 100
+          Height = 17
+          AutoSize = False
+          Caption = 'Filter by &extension:'
+          FocusControl = combo_extension
+        end
+        object combo_extension: TComboBox
+          Left = 2
+          Top = 60
+          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 = 2
+          OnClick = combo_extensionClick
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.31a/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.31a/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,809 @@
+UNIT Unit13_rawedit;
+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, Unit15_Classes,
+  Menus, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    structs: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    PROCEDURE structsDblClick(Sender: TObject);
+    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
+    fileid:LongWord;
+    dat_offset:LongWord;
+    fileid_opened,dat_offset_opened:LongWord;
+  PUBLIC
+  END;
+
+VAR
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    IF list_offset.Count=0 THEN BEGIN
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF OniDataConnection.ExtractFileID(list.Items.Strings[i])=raw_info.src_id THEN BEGIN
+          list.ItemIndex:=i;
+          listClick(Self);
+          Break;
+        END;
+      END;
+      FOR i:=0 TO list_offset.Count-1 DO BEGIN
+        IF MidStr(list_offset.Items.Strings[i],3,8)=IntToHex(raw_info.src_offset,8) THEN BEGIN
+          list_offset.ItemIndex:=i;
+          Break;
+        END;
+      END;
+    END;
+    Self.ClearStructViewer;
+    SetLength(data,raw_info.raw_size);
+    OniDataConnection.LoadRawFile(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      structs.Height:=structs.RowCount*20;
+      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+    count:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=OniDataConnection.GetExtensionsList;
+    FOR i:=0 TO High(RawListHandlers) DO BEGIN
+      count:=Length(OniDataConnection.GetFilesList(RawListHandlers[i].Ext,'',True));
+      combo_extension.Items.Add(RawListHandlers[i].ext+' ('+IntToStr(count)+')');
+    END;
+//    FOR i:=0 TO High(exts) DO
+//      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm13.LoadFileNames;
+  VAR
+    Extension:String;
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringArray;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN BEGIN
+      Extension:='';
+      FOR i:=0 TO High(RawListHandlers) DO BEGIN
+        IF Length(Extension)>0 THEN Extension:=Extension+',';
+        Extension:=Extension+RawListHandlers[i].Ext;
+      END;
+    END;
+
+    files:=OniDataConnection.GetFilesList(extension,pattern,TRUE);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    Self.ClearStructViewer;
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]);
+    list_offset.Enabled:=True;
+    IF OniDataConnection.GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=OniDataConnection.GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,8)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    Self.ClearStructViewer;
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,8));
+    LoadRaw(OniDataConnection.GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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 TForm13.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 TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of file '+OniDataConnection.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;
+          OniDataConnection.UpdateRawFile(fileid_opened,dat_offset_opened,Length(data),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+{      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+}    END;
+  END;
+
+PROCEDURE TForm13.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  BEGIN
+    saved.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(fileid).Extension+'|All files|*.*';
+    saved.DefaultExt:=OniDataConnection.GetFileInfo(fileid).Extension;
+    IF saved.Execute THEN BEGIN
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.btn_importClick(Sender: TObject);
+  VAR
+    data:Tdata;
+    fs:TFileStream;
+  BEGIN
+    opend.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+      IF datatype<>11 THEN BEGIN
+        objectname:=structure_infos[GetStructureInfoId(GetFileInfo(fileid).extension)].entries[structs.Row-1].name;
+        value:=GetValue(datatype,offset);
+        Form12.MakeVarInput(objectname,offset,datatype,value,Self);
+      END ELSE BEGIN
+        {LOAD RAW-EDITOR}
+      END;
+*)    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.31a/src/Unit14_settings.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit14_settings.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit14_settings.dfm	(revision 8)
@@ -0,0 +1,75 @@
+object Form14: TForm14
+  Left = 0
+  Top = 0
+  BorderStyle = bsToolWindow
+  Caption = 'Settings'
+  ClientHeight = 350
+  ClientWidth = 250
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object check_filesashex: TCheckBox
+    Left = 8
+    Top = 8
+    Width = 145
+    Height = 17
+    Caption = 'Show filenumbers as Hex'
+    TabOrder = 0
+  end
+  object btn_ok: TButton
+    Left = 8
+    Top = 319
+    Width = 57
+    Height = 23
+    Caption = 'OK'
+    Default = True
+    TabOrder = 1
+    OnClick = btn_okClick
+  end
+  object btn_cancel: TButton
+    Left = 120
+    Top = 319
+    Width = 57
+    Height = 23
+    Cancel = True
+    Caption = 'Cancel'
+    TabOrder = 2
+    OnClick = btn_cancelClick
+  end
+  object btn_register_oldb: TButton
+    Left = 8
+    Top = 128
+    Width = 169
+    Height = 25
+    Caption = 'Register .oldb files with OUP'
+    TabOrder = 3
+    OnClick = btn_register_oldbClick
+  end
+  object btn_register_opf: TButton
+    Left = 8
+    Top = 159
+    Width = 169
+    Height = 25
+    Caption = 'Register .opf files with OUP'
+    TabOrder = 4
+    OnClick = btn_register_opfClick
+  end
+  object btn_register_dat: TButton
+    Left = 8
+    Top = 97
+    Width = 169
+    Height = 25
+    Caption = 'Register .dat files with OUP'
+    TabOrder = 5
+    OnClick = btn_register_datClick
+  end
+end
Index: /oup/releases/0.31a/src/Unit14_settings.pas
===================================================================
--- /oup/releases/0.31a/src/Unit14_settings.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit14_settings.pas	(revision 8)
@@ -0,0 +1,155 @@
+unit Unit14_settings;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils;
+
+type
+  TForm14 = class(TForm)
+    check_filesashex: TCheckBox;
+    btn_ok: TButton;
+    btn_cancel: TButton;
+    btn_register_oldb: TButton;
+    btn_register_opf: TButton;
+    btn_register_dat: TButton;
+    procedure btn_register_opfClick(Sender: TObject);
+    procedure btn_register_oldbClick(Sender: TObject);
+    procedure btn_register_datClick(Sender: TObject);
+    procedure btn_cancelClick(Sender: TObject);
+    procedure btn_okClick(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormShow(Sender: TObject);
+    function RegisterExtension(ext:String):Integer;
+  private
+  public
+  end;
+
+var
+  Form14: TForm14;
+
+implementation
+{$R *.dfm}
+uses
+  Unit1_main, Unit3_data, ftypesAPI;
+
+function ExtensionRegistered(ext:String; var RegisteredAs:String):Boolean;
+  var
+    ftr:TFileTypeRegistration;
+  begin
+    ftr:=TFileTypeRegistration.Create;
+    if(ftr <> nil) then begin
+      try
+        RegisteredAs:=ftr.GetInternalKey(ext);
+        if RegisteredAs<>'' then
+          Result:=True
+        else
+          Result:=False;
+      finally
+        ftr.Free;
+      end;
+    end;
+  end;
+
+function TForm14.RegisterExtension(ext:String):Integer;
+  var
+    ftr:TFileTypeRegistration;
+    temps:String;
+    warnmsg:String;
+  begin
+    Result:=-1;
+    if ExtensionRegistered(ext,temps) then begin
+      if temps<>'ONI'+ext then begin
+        warnmsg:=ext+'-files are not registered to OUP but as "'+temps+'"-files.'+#13+#10+
+                 'Do you really want to unregister'+ext+'-files?';
+        if MessageBox(Self.Handle, PChar(warnmsg),PChar('Warning'),MB_YESNO)=ID_NO then
+          Exit;
+      end;
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then
+        try
+          if not ftr.UnregisterExtension(ext) then
+            ShowMessage('Could not unregister '+ext+'-files')
+          else
+            Result:=2;
+        finally
+          ftr.Free;
+        end;
+    end else begin
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then begin
+        try
+          if ftr.RegisterType(ext,'ONI'+ext,'ONI '+ext+'-file',Application.EXEname+',1') then begin
+            ftr.AddHandler('open','"'+Application.EXEname+'" '+MidStr(ext,2,Length(ext)-1)+' "%1"');
+            ftr.SetDefaultHandler;
+            Result:=1;
+          end;
+        finally
+          ftr.Free;
+        end;
+      end;
+    end;
+  end;
+
+procedure TForm14.btn_cancelClick(Sender: TObject);
+  begin
+    Self.Close;
+  end;
+
+procedure TForm14.btn_okClick(Sender: TObject);
+  begin
+    AppSettings.FilenumbersAsHex:=check_filesashex.Checked;
+    Self.Close;
+  end;
+
+procedure TForm14.btn_register_datClick(Sender: TObject);
+  begin
+    case RegisterExtension('.dat') of
+      2: btn_register_dat.Caption:='Register .dat files with OUP';
+      1: btn_register_dat.Caption:='Unregister .dat files';
+    end;
+  end;
+
+procedure TForm14.btn_register_oldbClick(Sender: TObject);
+  begin
+    case RegisterExtension('.oldb') of
+      2: btn_register_oldb.Caption:='Register .oldb files with OUP';
+      1: btn_register_oldb.Caption:='Unregister .oldb files';
+    end;
+  end;
+
+procedure TForm14.btn_register_opfClick(Sender: TObject);
+  begin
+    case RegisterExtension('.opf') of
+      2: btn_register_opf.Caption:='Register .opf files with OUP';
+      1: btn_register_opf.Caption:='Unregister .opf files';
+    end;
+  end;
+
+procedure TForm14.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  begin
+    CanClose:=False;
+    Self.Visible:=False;
+    Form1.Enabled:=True;
+    Form1.SetFocus;
+  end;
+
+procedure TForm14.FormShow(Sender: TObject);
+  var
+    temps:String;
+  begin
+    if ExtensionRegistered('.dat',temps) then
+      btn_register_dat.Caption:='Unregister .dat files'
+    else
+      btn_register_dat.Caption:='Register .dat files with OUP';
+    if ExtensionRegistered('.oldb',temps) then
+      btn_register_oldb.Caption:='Unregister .oldb files'
+    else
+      btn_register_oldb.Caption:='Register .oldb files with OUP';
+    if ExtensionRegistered('.opf',temps) then
+      btn_register_opf.Caption:='Unregister .opf files'
+    else
+      btn_register_opf.Caption:='Register .opf files with OUP';
+    check_filesashex.Checked:=AppSettings.FilenumbersAsHex;
+  end;
+
+end.
Index: /oup/releases/0.31a/src/Unit15_Classes.pas
===================================================================
--- /oup/releases/0.31a/src/Unit15_Classes.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit15_Classes.pas	(revision 8)
@@ -0,0 +1,1009 @@
+unit Unit15_Classes;
+interface
+uses Unit3_data, Unit9_data_structures, Classes, SysUtils, StrUtils, Dialogs, ABSDecUtil, ABSMain, DB;
+
+
+type
+  TOniData = class
+    private
+      FFileName:String;
+      FLevelInfo:TLevelInfo;
+      FBackend:Integer;
+      Fos_mac:Boolean;
+    protected
+    public
+      property FileName:String read FFileName write FFileName; 
+      property Backend:Integer read FBackend write FBackend;
+      property OSisMac:Boolean read Fos_mac write Fos_mac;
+      property LevelInfo:TLevelinfo read FLevelInfo write FLevelInfo;
+
+      constructor Create(filename:String; var Result:Boolean); virtual; abstract;
+      procedure Close; virtual; abstract;
+
+      function GetFileInfo(fileid:LongWord):TFileInfo; virtual; abstract;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; virtual; abstract;
+      function GetFilesCount:LongWord; virtual; abstract;
+      function GetExtensionsList:TStringArray; virtual; abstract;
+      function GetExtendedExtensionsList:TExtensionsMap; virtual; abstract;
+      function ExtractFileID(name:String):Integer;
+      function GetFileIDByName(name:String):Integer;
+
+      function LoadDatFile(fileid:LongWord):Tdata; virtual; abstract;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); virtual; abstract;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); virtual; abstract;
+
+      function GetRawList(fileid:LongWord):TRawList; virtual; abstract;
+      function GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); virtual; abstract;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); virtual; abstract;
+      function AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; virtual; abstract;//Returns new Address
+    published
+  end;
+
+  TOniDataDat = class(TOniData)
+    private
+      Fdat_file:TFileStream;
+      Fraw_file:TFileStream;
+      Fsep_file:TFileStream;
+      Fdat_header:THeader;
+      Fdat_filesmap:TFilesMap;
+      Fdat_files:TFiles;
+      Fdat_namedfilesmap:TNamedFilesMap;
+      Fdat_extensionsmap:TExtensionsMap;
+      FUnloadWhenUnused:Boolean;
+      FDatOpened:Boolean;
+      FRawOpened:Boolean;
+      FSepOpened:Boolean;
+    protected
+    public
+      property UnloadWhenUnused:Boolean read FUnloadWhenUnused write FUnloadWhenUnused;
+
+      constructor Create(DatFilename:String; var Result:Boolean); override;
+      procedure Close; override;
+
+      function GetFileInfo(fileid:LongWord):TFileInfo; override;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; override;
+      function GetFilesCount:LongWord; override;
+      function GetExtensionsList:TStringArray; override;
+      function GetExtendedExtensionsList:TExtensionsMap; override;
+
+      function LoadDatFile(fileid:LongWord):Tdata; override;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); override;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+
+      procedure LoadRawOffset(loc_sep:Boolean; raw_addr,size:LongWord; target:Pointer);
+      function GetRawList(fileid:LongWord):TRawList; override;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); override;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); override;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      function AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; override;//Returns new Address
+    published
+  end;
+
+  TOniDataADB = class(TOniData)
+    private
+      FDatabase:TABSDatabase;
+      FQuery:TABSQuery;
+    protected
+    public
+      constructor Create(OLDBFilename:String; var Result:Boolean); override;
+      procedure Close; override;
+
+      function GetFileInfo(fileid:LongWord):TFileInfo; override;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; override;
+      function GetFilesCount:LongWord; override;
+      function GetExtensionsList:TStringArray; override;
+      function GetExtendedExtensionsList:TExtensionsMap; override;
+
+      function LoadDatFile(fileid:LongWord):Tdata; override;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); override;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+
+      function GetRawList(fileid:LongWord):TRawList; override;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); override;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); override;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+    published
+  end;
+
+
+const
+  ODB_None=-1;
+  ODB_Dat=0;
+  ODB_ADB=1;
+
+var
+  OniDataConnection:TOniData;
+
+function CreateDataConnection(filename:String; backend:Integer):Boolean;
+procedure CloseDataConnection;
+
+
+
+
+implementation
+uses Unit2_Functions;
+
+
+
+(*
+  Implementation of  TOniData
+*)
+
+function TOniData.GetFileIDByName(name:String):Integer;
+  var
+    files:TStringArray;
+    i: Integer;
+  begin
+    Result:=-1;
+    files:=Self.GetFilesList('',name,false);
+    if Length(files)>0 then
+      for i:=0 to High(files) do
+        if Pos(name,files[i])=Pos('-',files[i])+1 then begin
+//        if MidStr(files[i],Pos('-',files[i])+1,Length(files[i])-Pos('-',files[i])-5)=name then begin
+          Result:=Self.ExtractFileID(files[i]);
+          Break;
+        end;
+  end;
+
+function TOniData.ExtractFileID(name:String):Integer;
+  begin
+    if name[5]='-' then
+      Result:=HexToLong(MidStr(name,1,4))
+    else
+      Result:=StrToInt(MidStr(name,1,5));
+  end;
+
+function TOniData.GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  var
+    i:LongWord;
+    raw_list:TRawList;
+  begin
+    raw_list:=Self.GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    for i:=0 to High(raw_list) do begin
+      if raw_list[i].src_offset=dat_offset then begin
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Result.loc_sep:=raw_list[i].loc_sep;
+        Break;
+      end;
+    end;
+  end;
+
+
+
+
+
+
+
+(*
+================================================================================
+                      Implementation of  TOniDataDat
+*)
+
+constructor TOniDataDat.Create(DatFilename:String; var Result:Boolean);
+  const
+    header_ident1_pc: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_ident1_mac:Array[0..$13] of Byte=
+        ($61,$30,$C1,$23,$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);
+  var
+    i:LongWord;
+    header_pc,header_mac:Boolean;
+  begin
+    FUnloadWhenUnused:=True;
+    FDatOpened:=False;
+    FRawOpened:=False;
+    if not FileExists(DatFilename) then begin
+      ShowMessage('File doesn''t exist!!!');
+      Result:=False;
+      Exit;
+    end;
+    FFileName:=DatFilename;
+    Fdat_file:=TFileStream.Create(FFileName, fmOpenRead);
+    Fdat_file.Read(Fdat_header,SizeOf(Fdat_header));
+    header_pc:=True;
+    header_mac:=True;
+    for i:=0 to High(Fdat_header.Ident) do begin
+      FLevelInfo.Ident[i]:=Fdat_header.Ident[i];
+      if Fdat_header.Ident[i]<>header_ident1_pc[i] then begin
+        header_pc:=False;
+      end;
+      if Fdat_header.Ident[i]<>header_ident1_mac[i] then begin
+        header_mac:=False;
+      end;
+    end;
+    if not (header_pc xor header_mac) then begin
+      Result:=False;
+      Exit;
+    end else begin
+      if (header_pc and not header_mac) then
+        Fos_mac:=False
+      else
+        Fos_mac:=True;
+    end;
+    SetLength(Fdat_filesmap,Fdat_header.Files);
+    SetLength(Fdat_files,Fdat_header.Files);
+    for i:=0 to Fdat_header.Files-1 do
+      Fdat_file.Read(Fdat_filesmap[i],SizeOf(Fdat_filesmap[i]));
+    for i:=0 to Fdat_header.Files-1 do begin
+      Fdat_files[i].Extension:=Fdat_filesmap[i].Extension;
+      Fdat_files[i].Extension:=ReverseString(Fdat_files[i].Extension);
+      Fdat_files[i].Size:=Fdat_filesmap[i].FileSize;
+      Fdat_files[i].FileType:=Fdat_filesmap[i].FileType;
+      Fdat_files[i].DatAddr:=Fdat_filesmap[i].DataAddr-8+Fdat_header.DataAddr;
+      if (Fdat_filesmap[i].FileType and $01)=0 then begin
+        Fdat_file.Seek(Fdat_filesmap[i].NameAddr+Fdat_header.NamesAddr,soFromBeginning);
+        SetLength(Fdat_files[i].Name,100);
+        Fdat_file.Read(Fdat_files[i].Name[1],100);
+        Fdat_files[i].Name:=MidStr(Fdat_files[i].Name,1+4,Pos(#0,Fdat_files[i].Name)-1-4);
+      end else begin
+        Fdat_files[i].Name:='';
+      end;
+      Fdat_files[i].FileName:=FormatNumber(i,5,'0')+'-'+Fdat_files[i].Name+'.'+Fdat_files[i].Extension;
+      Fdat_files[i].FileNameHex:=IntToHex(i,4)+'-'+Fdat_files[i].Name+'.'+Fdat_files[i].Extension;
+    end;
+    Fdat_file.Seek($40+Fdat_header.Files*$14,soFromBeginning);
+    SetLength(Fdat_namedfilesmap,Fdat_header.NamedFiles);
+    for i:=0 to Fdat_header.NamedFiles-1 do
+      Fdat_file.Read(Fdat_namedfilesmap[i],SizeOf(Fdat_namedfilesmap[i]));
+
+    Fdat_file.Seek($40+Fdat_header.Files*$14+Fdat_header.NamedFiles*$8,soFromBeginning);
+    SetLength(Fdat_extensionsmap,Fdat_header.Extensions);
+    for i:=0 to Fdat_header.Extensions-1 do
+      Fdat_file.Read(Fdat_extensionsmap[i],SizeOf(Fdat_extensionsmap[i]));
+
+    Fdat_file.Seek(Fdat_files[0].DatAddr+7,soFromBeginning);
+    Fdat_file.Read(FLevelInfo.LevelNumber,1);
+    FLevelInfo.LevelNumber:=FLevelInfo.LevelNumber DIV 2;
+
+    Fdat_file.Free;
+
+    Result:=True;
+    FBackend:=ODB_Dat;
+  end;
+
+procedure TOniDataDat.Close;
+  begin
+    if not FUnloadWhenUnused and FDatOpened then
+      Fdat_file.Free;
+    if not FUnloadWhenUnused and FRawOpened then
+      Fraw_file.Free;
+    if not FUnloadWhenUnused and FSepOpened then
+      Fsep_file.Free;
+    Self.Free;
+  end;
+
+
+
+function TOniDataDat.GetFileInfo(fileid:LongWord):TFileInfo;
+  begin
+    if fileid<Self.GetFilesCount then
+      Result:=Fdat_files[fileid]
+    else
+      Result.ID:=-1;
+  end;
+
+function TOniDataDat.GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    for i:=0 to Fdat_header.Files-1 do begin
+      if ( (Length(ext)=0) or (Pos(Fdat_files[i].Extension,ext)>0) ) and
+          ( (Length(pattern)=0) or (Pos(UpperCase(pattern),UpperCase(Fdat_files[i].Name))>0) ) then begin
+          if (NoEmptyFiles=false) or ((Fdat_files[i].FileType and $02)=0) then begin
+            SetLength(Result,Length(Result)+1);
+            if AppSettings.FilenumbersAsHex then
+              Result[High(Result)]:=Fdat_files[i].FileNameHex
+            else
+              Result[High(Result)]:=Fdat_files[i].FileName;
+          end;
+      end;
+    end;
+  end;
+
+function TOniDataDat.GetFilesCount:LongWord;
+  begin
+    Result:=Fdat_header.Files;
+  end;
+
+function TOniDataDat.GetExtensionsList:TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,Fdat_header.Extensions);
+    for i:=0 to Fdat_header.Extensions-1 do begin
+      with Fdat_extensionsmap[i] do begin
+        Result[i]:=Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+IntToStr(ExtCount)+')';
+      end;
+    end;
+  end;
+
+function TOniDataDat.GetExtendedExtensionsList:TExtensionsMap;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,Fdat_header.Extensions);
+    for i:=0 to Fdat_header.Extensions-1 do begin
+      Result[i]:=Fdat_extensionsmap[i];
+    end;
+  end;
+
+
+function TOniDataDat.LoadDatFile(fileid:LongWord):Tdata;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      if FUnloadWhenUnused or not FDatOpened then
+        Fdat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      Fdat_file.Seek(Fdat_files[fileid].DatAddr,soFromBeginning);
+      SetLength(Result,Fdat_files[fileid].Size);
+      Fdat_file.Read(Result[0],Fdat_files[fileid].Size);
+      if UnloadWhenUnused then
+        Fdat_file.Free
+      else
+        FDatOpened:=True;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateDatFile(fileid:LongWord; data:Tdata);
+  begin
+    if fileid<Self.GetFilesCount then begin
+      if FUnloadWhenUnused or not FDatOpened then
+        Fdat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      Fdat_file.Seek(Fdat_files[fileid].DatAddr,soFromBeginning);
+      Fdat_file.Write(data[0],Length(data));
+      if UnloadWhenUnused then
+        Fdat_file.Free
+      else
+        FDatOpened:=True;
+    end;
+  end;
+
+procedure TOniDataDat.LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  begin
+    if fileid<Self.GetFilesCount then begin
+      if FUnloadWhenUnused or not FDatOpened then
+        Fdat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      Fdat_file.Seek(Fdat_files[fileid].DatAddr+offset,soFromBeginning);
+      Fdat_file.Read(target^,size);
+      if UnloadWhenUnused then
+        Fdat_file.Free
+      else
+        FDatOpened:=True;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  begin
+    if fileid<Self.GetFilesCount then begin
+      if FUnloadWhenUnused or not FDatOpened then
+        Fdat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      Fdat_file.Seek(Fdat_files[fileid].DatAddr+offset,soFromBeginning);
+      Fdat_file.Write(target^,size);
+      Fdat_file.Free;
+      if UnloadWhenUnused then
+        Fdat_file.Free
+      else
+        FDatOpened:=True;
+    end;
+  end;
+
+
+
+function TOniDataDat.GetRawList(fileid:LongWord):TRawList;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    for i:=0 to High(RawListHandlers) do
+      if UpperCase(RawListHandlers[i].Ext)=UpperCase(Fdat_files[fileid].extension) then
+        if RawListHandlers[i].needed then begin
+          Result:=RawListHandlers[i].Handler(fileid);
+          Break;
+        end else
+          Break;
+  end;
+
+procedure TOniDataDat.LoadRawOffset(loc_sep:Boolean; raw_addr,size:LongWord; target:Pointer);
+  begin
+    if not loc_sep then begin
+      if FUnloadWhenUnused or not FRawOpened then
+        Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+      if raw_addr<=Fraw_file.Size then begin
+        Fraw_file.Seek(raw_addr,soFromBeginning);
+        Fraw_file.Read(target^,size);
+      end;
+      if UnloadWhenUnused then
+        Fraw_file.Free
+      else
+        FRawOpened:=True
+    end else begin
+      if FUnloadWhenUnused or not FSepOpened then
+        Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+      if raw_addr<=Fsep_file.Size then begin
+        Fsep_file.Seek(raw_addr,soFromBeginning);
+        Fsep_file.Read(target^,size);
+      end;
+      if UnloadWhenUnused then
+        Fsep_file.Free
+      else
+        FSepOpened:=True;
+    end;
+  end;
+
+procedure TOniDataDat.LoadRawFile(fileid,dat_offset:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then begin
+        if FUnloadWhenUnused or not FRawOpened then
+          Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+        Fraw_file.Seek(raw_info.raw_addr,soFromBeginning);
+        Fraw_file.Read(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fraw_file.Free
+        else
+          FRawOpened:=True
+      end else begin
+        if FUnloadWhenUnused or not FSepOpened then
+          Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+        Fsep_file.Seek(raw_info.raw_addr,soFromBeginning);
+        Fsep_file.Read(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fsep_file.Free
+        else
+          FSepOpened:=True;
+      end;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then begin
+        if FUnloadWhenUnused or not FRawOpened then
+          Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+        Fraw_file.Seek(raw_info.raw_addr,soFromBeginning);
+        Fraw_file.Write(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fraw_file.Free
+        else
+          FRawOpened:=True
+      end else begin
+        if FUnloadWhenUnused or not FSepOpened then
+          Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+        Fsep_file.Seek(raw_info.raw_addr,soFromBeginning);
+        Fsep_file.Write(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fsep_file.Free
+        else
+          FSepOpened:=True;
+      end;
+    end;
+  end;
+
+procedure TOniDataDat.LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+    data:Tdata;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      SetLength(data, raw_info.raw_size);
+      Self.LoadRawFile(fileid,dat_offset,@data[0]);
+      mem:=TMemoryStream.Create;
+      mem.Write(data[offset],size);
+      mem.Read(target^,size);
+      mem.Free;  
+    end;
+  end;
+
+procedure TOniDataDat.UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then begin
+        if FUnloadWhenUnused or not FRawOpened then
+          Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+        Fraw_file.Seek(raw_info.raw_addr+offset,soFromBeginning);
+        Fraw_file.Write(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fraw_file.Free
+        else
+          FRawOpened:=True
+      end else begin
+        if FUnloadWhenUnused or not FSepOpened then
+          Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+        Fsep_file.Seek(raw_info.raw_addr+offset,soFromBeginning);
+        Fsep_file.Write(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fsep_file.Free
+        else
+          FSepOpened:=True;
+      end;
+    end;
+  end;
+
+function TOniDataDat.AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; //Returns new Address
+  begin
+    if not loc_sep then begin
+      if FUnloadWhenUnused or not FRawOpened then
+        Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+      Result:=Fraw_file.Size;
+      Fraw_file.Seek(0,soFromEnd);
+      Fraw_file.Write(target^,size);
+      if UnloadWhenUnused then
+        Fraw_file.Free
+      else
+        FRawOpened:=True
+    end else begin
+      if FUnloadWhenUnused or not FSepOpened then
+        Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+      Result:=Fsep_file.Size;
+      Fsep_file.Seek(0,soFromEnd);
+      Fsep_file.Write(target^,size);
+      if UnloadWhenUnused then
+        Fsep_file.Free
+      else
+        FSepOpened:=True;
+    end;
+  end;
+
+
+
+
+
+
+
+
+
+  
+
+(*
+================================================================================
+                     Implementation of  TOniDataADB
+*)
+
+constructor TOniDataADB.Create(OLDBFilename:String; var Result:Boolean);
+  var
+    i,j:Byte;
+    temps:String;
+  begin
+    if not FileExists(OLDBFilename) then begin
+      ShowMessage('File doesn''t exist!!!');
+      Result:=False;
+      Exit;
+    end;
+    FFileName:=OLDBFilename;
+    FDatabase:=TABSDatabase.Create(nil);
+    FDatabase.DatabaseName:='OLDBcon';
+    FDatabase.DatabaseFileName:=OLDBFilename;
+    FDatabase.Open;
+    FQuery:=TABSQuery.Create(FDatabase);
+    FQuery.DatabaseName:='OLDBcon';
+    FQuery.SQL.Text:='SELECT [name],[value] FROM globals ORDER BY [name] ASC';
+    FQuery.Open;
+    FQuery.First;
+    repeat
+      if FQuery.FieldByName('name').AsString='dbversion' then begin
+        if FQuery.FieldByName('value').AsString<>DBversion then begin
+          ShowMessage('Database-file '+#13+#10+
+                      '"'+OLDBFilename+'"'+#13+#10+
+                      'has wrong version. (Required: '+DBversion+'; found: '+
+                        FQuery.FieldByName('value').AsString+')');
+          FQuery.Close;
+          Result:=False;
+          Exit;
+        end;
+      end;
+      if FQuery.FieldByName('name').AsString='lvl' then begin
+        FLevelInfo.LevelNumber:=StrToInt(FQuery.FieldByName('value').AsString);
+      end;
+      if FQuery.FieldByName('name').AsString='ident' then begin
+        temps:=FQuery.FieldByName('value').AsString;
+        for i:=0 to High(FLevelInfo.Ident) do begin
+          j:=i*2+1;
+          case temps[j] of
+            '0'..'9': FLevelInfo.Ident[i]:=Ord(temps[j])-48;
+            'A'..'F': FLevelInfo.Ident[i]:=Ord(temps[j])-55;
+          end;
+          FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]*16;
+          case temps[j+1] of
+            '0'..'9': FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]+Ord(temps[j+1])-48;
+            'A'..'F': FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]+Ord(temps[j+1])-55;
+          end;
+        end;
+      end;
+      if FQuery.FieldByName('name').AsString='ident' then begin
+        temps:=FQuery.FieldByName('value').AsString;
+        Fos_mac:=temps='MAC';
+      end;
+      FQuery.Next;
+    until FQuery.EoF;
+    FQuery.Close;
+
+    Result:=True;
+    FBackend:=ODB_ADB;
+  end;
+
+procedure TOniDataADB.Close;
+  begin
+    FDatabase.Close;
+    FDatabase.Free;
+    Self.Free;
+  end;
+
+
+
+function TOniDataADB.GetFileInfo(fileid:LongWord):TFileInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT * FROM datfiles WHERE id='+IntToStr(fileid)+' ORDER BY id ASC;';
+      FQuery.Open;
+      if FQuery.RecordCount=1 then begin
+        FQuery.First;
+        Result.ID:=FQuery.FieldByName('id').AsInteger;
+        Result.Name:=FQuery.FieldByName('name').AsString;
+        Result.Extension:=FQuery.FieldByName('extension').AsString;
+        Result.FileName:=FormatNumber(Result.ID,5,'0')+'-'+Result.Name+'.'+Result.Extension;
+        Result.Size:=FQuery.FieldByName('size').AsInteger;
+        Result.FileType:=FQuery.FieldByName('contenttype').AsInteger;
+        Result.DatAddr:=0;
+        Result.opened:=False;
+      end;
+      FQuery.Close;
+    end else begin
+      Result.ID:=-1;
+    end;
+  end;
+
+function TOniDataADB.GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray;
+  var
+    i:LongWord;
+    where:String;
+    where_ext:String;
+  begin
+    where:='';
+    if Length(ext)>0 then begin
+      if Length(where)>0 then
+        where:=where+' AND ';
+      if Pos(',',ext)>0 then begin
+        i:=1;
+        where_ext:='';
+        while i<Length(ext) do begin
+          if Length(where_ext)>0 then
+            where_ext:=where_ext+' OR ';
+          where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")';
+          i:=i+5;
+        end;
+        where:=where+'('+where_ext+')';
+      end else begin
+        where:=where+'(extension="'+ext+'")';
+      end;
+    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;
+    FQuery.SQL.Text:='SELECT id,name,extension FROM datfiles'+where+' ORDER BY id ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i]:=FormatNumber(FQuery.FieldByName('id').AsInteger,5,'0')+'-'+FQuery.FieldByName('name').AsString+'.'+FQuery.FieldByName('extension').AsString;
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetFilesCount:LongWord;
+  begin
+    FQuery.SQL.Text:='SELECT Count(*) AS cnumber FROM datfiles;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      Result:=FQuery.FieldByName('cnumber').AsInteger;
+    end else Result:=0;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetExtensionsList:TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    FQuery.SQL.Text:='SELECT extension,count(extension) AS x FROM datfiles GROUP BY extension ORDER BY extension ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i]:=FQuery.FieldByName('extension').AsString+' ('+IntToStr(FQuery.FieldByName('x').AsInteger)+')';
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetExtendedExtensionsList:TExtensionsMap;
+  var
+    i,j:LongWord;
+    temps:String;
+    data:Tdata;
+  begin
+    SetLength(Result,0);
+    FQuery.SQL.Text:='SELECT extension,ident FROM extlist ORDER BY extension ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        temps:=FQuery.FieldByName('extension').AsString;
+        for j:=0 to 3 do Result[i].Extension[j]:=temps[3-j];
+        data:=DecodeHexString(FQuery.FieldByName('ident').AsString);
+        for j:=0 to 7 do Result[i].Ident[j]:=data[j];
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+
+
+
+function TOniDataADB.LoadDatFile(fileid:LongWord):Tdata;
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';';
+      FQuery.Open;
+      if FQuery.RecordCount>0 then begin
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        SetLength(Result,mem.Size);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(Result[0],mem.Size);
+        mem.Free;
+      end;
+      FQuery.Close;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateDatFile(fileid:LongWord; data:Tdata);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE datfiles SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE id='+IntToStr(fileid)+';';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+procedure TOniDataADB.LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';';
+      FQuery.Open;
+      IF FQuery.RecordCount>0 THEN BEGIN
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        mem.Seek(offset,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+      FQuery.Close;
+    END;
+  END;
+
+procedure TOniDataADB.UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+    data:Tdata;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      data:=Self.LoadDatFile(fileid);
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(offset,soFromBeginning);
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE datfiles SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE id='+IntToStr(fileid)+';';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+
+
+function TOniDataADB.GetRawList(fileid:LongWord):TRawList;
+  var
+    i:LongWord;
+    Query:TABSQuery;
+  begin
+    SetLength(Result,0);
+    FQuery.SQL.Text:='SELECT [src_link_offset],[size] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i].src_id:=fileid;
+        Result[i].src_offset:=FQuery.FieldByName('src_link_offset').AsInteger;
+        Result[i].raw_addr:=0;
+        Result[i].raw_size:=FQuery.FieldByName('size').AsInteger;
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+  
+procedure TOniDataADB.LoadRawFile(fileid,dat_offset:LongWord; target:Pointer);
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.Open;
+      if FQuery.RecordCount>0 then begin
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      end;
+      FQuery.Close;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE rawmap SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+procedure TOniDataADB.LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    data:Tdata;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      SetLength(data, Self.GetRawInfo(fileid,dat_offset).raw_size);
+      Self.LoadRawFile(fileid,dat_offset,@data[0]);
+      mem:=TMemoryStream.Create;
+      mem.Write(data[offset],size);
+      mem.Read(target^,size);
+      mem.Free;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+    data:Tdata;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      SetLength(data, Self.GetRawInfo(fileid,offset).raw_size);
+      Self.LoadRawFile(fileid,offset,@data[0]);
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(offset,soFromBeginning);
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE rawmap SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+
+
+
+
+
+
+
+
+
+
+function CreateDataConnection(filename:String; backend:Integer):Boolean;
+  var
+    answer:Boolean;
+  begin
+    if Assigned(OniDataConnection) then begin
+      OniDataConnection.Close;
+      OniDataConnection.Free;
+      OniDataConnection:=Nil;
+    end;
+    case backend of
+      ODB_Dat: OniDataConnection:=TOniDataDat.Create(filename, answer);
+      ODB_ADB: OniDataConnection:=TOniDataADB.Create(filename, answer);
+    else
+      ShowMessage('Unknown Backend');
+      Result:=False;
+      Exit;
+    end;
+
+    if answer then begin
+//      ShowMessage('file loaded');
+//      ShowMessage('Files: '+IntToStr(OniDataConnection.GetFilesCount));
+      Result:=True;
+    end else begin
+      ShowMessage('File not loaded');
+      OniDataConnection.Close;
+      OniDataConnection.Free;
+      Result:=False;
+    end;
+  end;
+
+procedure CloseDataConnection;
+  begin
+    if Assigned(OniDataConnection) then begin
+      OniDataConnection.Close;
+      OniDataConnection:=Nil;
+    end;
+  end;
+
+end.
Index: /oup/releases/0.31a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  Caption = 'Form1'
+  ClientHeight = 495
+  ClientWidth = 577
+  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 = 478
+    Width = 577
+    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
+    ExplicitTop = 459
+  end
+  object tabs: TTabSet
+    Left = 0
+    Top = 458
+    Width = 577
+    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
+    ExplicitTop = 439
+  end
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 328
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 424
+    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_CloseFileDB: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = menu_CloseFileDBClick
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_settings: TMenuItem
+        Caption = 'Se&ttings...'
+        OnClick = menu_settingsClick
+      end
+      object menu_sep4: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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
+    object menu_About: TMenuItem
+      Caption = '&About'
+      OnClick = menu_AboutClick
+    end
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 376
+  end
+end
Index: /oup/releases/0.31a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.31a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,527 @@
+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, Unit9_data_structures,
+  Unit10_leveldb, Unit4_exporters, Unit14_settings,
+  Unit5_preview, Unit7_txmpreplace, Unit8_binedit, Unit11_extractor, Unit13_rawedit,
+  Unit15_Classes;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    menu_CloseFileDB: TMenuItem;
+    menu_sep4: TMenuItem;
+    menu_settings: TMenuItem;
+    menu_About: TMenuItem;
+    FUNCTION TryCloseAll:Boolean;
+    procedure menu_AboutClick(Sender: TObject);
+    PROCEDURE menu_settingsClick(Sender: TObject);
+    PROCEDURE menu_CloseFileDBClick(Sender: TObject);
+    PROCEDURE menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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);
+    PROCEDURE UpdateStatBar;
+  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;
+
+    IF MidStr(ParamStr(1),1,3)='opf' THEN BEGIN
+      ShowMessage('Load OPF-File: '+ParamStr(2));
+    END ELSE IF MidStr(ParamStr(1),1,4)='oldb' THEN BEGIN
+      IF NOT CreateDataConnection(ParamStr(2), ODB_ADB) THEN
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an OniUnPacker-LevelDatabase-file?');
+    END ELSE IF MidStr(ParamStr(1),1,3)='dat' THEN BEGIN
+      IF NOT CreateDataConnection(ParamStr(2), ODB_Dat) THEN
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an Oni-.dat-file?');
+    END;
+    UpdateStatBar;
+  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;
+
+
+PROCEDURE TForm1.UpdateStatBar;
+  BEGIN
+    IF Assigned(OniDataConnection) THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(OniDataConnection.FileName)+')';
+      menu_tools.Enabled:=True;
+      menu_convert.Enabled:=False;
+      statbar.Panels.Items[1].Text:='Files: '+IntToStr(OniDataConnection.GetFilesCount);
+      statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(OniDataConnection.GetExtensionsList));
+      CASE OniDataConnection.Backend OF
+        ODB_Dat:
+          BEGIN
+            statbar.Panels.Items[0].Text:='.dat loaded: '+OniDataConnection.FileName;
+          END;
+        ODB_ADB:
+          BEGIN
+            statbar.Panels.Items[0].Text:='OLDB loaded: '+OniDataConnection.FileName;
+          END;
+      ELSE
+        Form1.Caption:='Oni Un/Packer '+version;
+        statbar.Panels.Items[0].Text:='Nothing loaded';
+        statbar.Panels.Items[1].Text:='Files: -';
+        statbar.Panels.Items[2].Text:='Extensions: -';
+        menu_tools.Enabled:=False;
+        menu_convert.Enabled:=True;
+      END;
+    END ELSE BEGIN
+      Form1.Caption:='Oni Un/Packer '+version;
+      statbar.Panels.Items[0].Text:='Nothing loaded';
+      statbar.Panels.Items[1].Text:='Files: -';
+      statbar.Panels.Items[2].Text:='Extensions: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+
+
+FUNCTION TForm1.TryCloseAll:Boolean;
+  BEGIN
+    menu_windows_closeallClick(Self);
+    IF Length(tablist)=0 THEN
+      Result:=True
+    ELSE
+      Result:=False;
+  END;
+
+
+{#################################}
+{##### Main-Menu-Handlers    #####}
+{#################################}
+PROCEDURE TForm1.menu_loaddatClick(Sender: TObject);
+  VAR i:LongWord;
+    answer:Boolean;
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      opend.InitialDir:=AppSettings.DatPath;
+      opend.Filter:='Oni-Dat-Files|*.dat';
+      IF opend.Execute THEN BEGIN
+        IF NOT CreateDataConnection(opend.FileName, ODB_Dat) THEN
+          ShowMessage('Error while loading the file:'+CrLf+opend.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+        AppSettings.DatPath:=ExtractFilepath(opend.FileName);
+      END;
+    END;
+    UpdateStatBar;
+  END;
+PROCEDURE TForm1.menu_lvldbClick(Sender: TObject);
+  VAR answer:Boolean;
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      opend.InitialDir:=AppSettings.DatPath;
+      opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+      IF opend.Execute THEN BEGIN
+        IF NOT CreateDataConnection(opend.FileName, ODB_ADB) THEN
+          ShowMessage('Error while loading the file:'+CrLf+opend.FileName+CrLf+'Perhaps not an OniUnPacker-LevelDatabase-file?');
+        AppSettings.DatPath:=ExtractFilepath(opend.FileName);
+      END;
+    END;
+    UpdateStatBar;
+  END;
+PROCEDURE TForm1.menu_CloseFileDBClick(Sender: TObject);
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      UpdateStatBar;
+    END;
+  END;
+PROCEDURE TForm1.menu_settingsClick(Sender: TObject);
+  BEGIN
+    Form14.Visible:=True;
+    Self.Enabled:=False;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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.menu_AboutClick(Sender: TObject);
+  begin
+    ShowMessage('Will be implemented later ;)');
+  end;
+
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.31a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.31a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,266 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data;
+
+TYPE
+  TExportSet=SET OF (DO_dat,DO_raw,DO_convert,DO_toone);
+
+FUNCTION HexToLong(hex:String):LongWord;
+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 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 DecodeHexString(hex:String):Tdata;
+FUNCTION GetWinFileName(name:String):String;
+FUNCTION GetExtractPath:String;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringArray;
+
+
+IMPLEMENTATION
+USES Unit4_Exporters, Unit15_Classes;
+
+TYPE
+  TValueSwitcher=Record
+    CASE IsFloat: Boolean OF
+      True: (ValueFloat:Single);
+      False: (ValueInt:LongWord);
+  END;
+
+
+FUNCTION HexToLong(hex:String):LongWord;
+  FUNCTION NormalizeHexString(VAR hex:String):Boolean;
+    VAR
+      i:Byte;
+    BEGIN
+      IF hex[1]='$' THEN BEGIN
+        FOR i:=1 TO Length(hex)-1 DO BEGIN
+          hex[i]:=hex[i+1];
+        END;
+        SetLength(hex, Length(hex)-1);
+      END;
+      IF (hex[1]='0') AND (UpCase(hex[2])='X') THEN BEGIN
+        FOR i:=1 TO Length(hex)-2 DO BEGIN
+          hex[i]:=hex[i+2];
+        END;
+        SetLength(hex, Length(hex)-2);
+      END;
+      IF Length(hex)=0 THEN
+        Result:=False
+      ELSE
+        Result:=True;
+    END;
+  VAR
+    i:Byte;
+  BEGIN
+    IF NormalizeHexString(hex) THEN BEGIN
+      hex:=UpperCase(hex);
+      Result:=0;
+      FOR i:=1 TO Length(hex) DO BEGIN
+        Result:=Result SHL 4;
+        CASE hex[i] OF
+          '0'..'9': Result:=Result+Ord(hex[i])-48;
+          'A'..'F': Result:=Result+Ord(hex[i])-55;
+        ELSE
+          Result:=0;
+          Exit;
+        END;
+      END;
+    END ELSE BEGIN
+      Result:=0;
+    END;
+  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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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 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 DecodeHexString(hex:String):Tdata;
+  VAR
+    i:LongWord;
+  BEGIN
+    SetLength(Result, Length(hex) DIV 2);
+    FOR i:=0 TO Length(Result) DO BEGIN
+      Result[i]:=0;
+      CASE UpCase(hex[i*2]) OF
+        '0'..'9': Result[i]:=(Ord(hex[i])-48)*16;
+        'A'..'F': Result[i]:=(Ord(hex[i])-55)*16;
+      END;
+      CASE UpCase(hex[i*2+1]) OF
+        '0'..'9': Result[i]:=Result[i]+(Ord(hex[i])-48);
+        'A'..'F': Result[i]:=Result[i]+(Ord(hex[i])-55);
+      END;
+    END;
+  END;
+
+
+FUNCTION ExportFile(fileid:LongWord; filename:String; settings:TExportSet; path:String):Integer;
+  VAR
+    i:Byte;
+    extension:String;
+    rawlist:TRawList;
+  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
+        rawlist:=OniDataConnection.GetRawList(fileid);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR i:=0 TO High(rawlist) DO BEGIN
+            ExportRawFile(fileid,rawlist[i].src_offset,path+'\'+GetWinFileName(filename));
+          END;
+        END;
+      END;
+    END;
+  END;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringArray;
+  VAR
+    start,len:Word;
+  BEGIN
+    SetLength(Result, 0);
+    start:=1;
+    WHILE PosEx(delimiter,_string,start)>0 DO BEGIN
+      len:=PosEx(delimiter,_string,start)-start;
+      SetLength(Result, Length(Result)+1);
+      Result[High(Result)]:=MidStr(_string,start,len);
+      start:=start+len+1;
+    END;
+    SetLength(Result, Length(Result)+1);
+    Result[High(Result)]:=MidStr(_string,start,Length(_string)-start+1);
+  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(OniDataConnection.FileName)+'\extracted_'+ExtractFileName(OniDataConnection.Filename);
+  END;
+
+
+END.
Index: /oup/releases/0.31a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.31a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,123 @@
+unit Unit3_data;
+interface
+uses Classes;
+
+const
+  Version:String='v0.31a';
+  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:Integer;
+    FileName:String;
+    FileNameHex: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;
+
+  TLevelInfo=Record
+    Ident:Array[0..$13] of Byte;
+    LevelNumber:Byte;
+  end;
+
+  TAppSettings=Record
+    DatPath:String[250];
+    ExtractPath:String[250];
+    FilenumbersAsHex:Boolean;
+  end;
+
+  TExportHandlers=Record
+    Ext:String[4];
+    needed:Boolean;
+    Handler:Function(fileid:LongWord; filename:String; convert:Boolean):Integer;
+  end;
+
+  TStringArray=Array of String;
+  TExtList=Array of Record
+    Ext:String;
+    count:LongWord;
+  end;
+
+  TRawInfo=Record
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+    loc_sep:Boolean;
+  end;
+  TRawList=Array of TRawInfo;
+
+var
+{
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_os_mac:Boolean=False;
+  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_pc: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_ident1_mac:Array[0..$13] of Byte=
+      ($61,$30,$C1,$23,$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.31a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.31a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,218 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, Dialogs, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset: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, Unit9_data_structures, Unit15_Classes;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=OniDataConnection.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;
+
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    SetLength(data, OniDataConnection.GetRawInfo(fileid, dat_offset).raw_size);
+    OniDataConnection.LoadRawFile(fileid,dat_offset,@data[0]);
+    IF FileExists(filename+'.raw0x'+IntToHex(dat_offset,8)) THEN BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd);
+    END ELSE BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),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;
+    OniDataConnection.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);
+        OniDataConnection.LoadRawFile(fileid,$44,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;
+
+    OniDataConnection.LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+
+    OniDataConnection.LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    FOR i:=1 TO linkcount DO BEGIN
+      OniDataConnection.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;
+
+    OniDataConnection.LoadDatFilePart(fileid,$14,SizeOf(loop_speed),@loop_speed);
+    OniDataConnection.LoadDatFilePart(fileid,$16,SizeOf(unknown),@unknown);
+
+    OniDataConnection.LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      OniDataConnection.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.31a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Caption = 'Preview'
+  ClientHeight = 473
+  ClientWidth = 472
+  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.31a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.31a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,281 @@
+UNIT Unit5_preview;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Math, ExtCtrls, StdCtrls, StrUtils, Menus,
+  Unit2_functions, Unit3_data, Unit4_exporters, Unit6_imgfuncs, Unit15_Classes;
+
+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
+    memstreams:Array OF TMemoryStream;
+    actualimg:Byte;
+    _fileid:LongWord;
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+
+
+PROCEDURE TForm5.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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:=OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]);
+    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
+    OniDataConnection.LoadDatFilePart(_fileid,$14,SizeOf(loop_speed),@loop_speed);
+    OniDataConnection.LoadDatFilePart(_fileid,$1C,SizeOf(linkcount),@linkcount);
+    SetLength(memstreams,linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      OniDataConnection.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 '+OniDataConnection.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 '+OniDataConnection.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 '+OniDataConnection.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.31a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.31a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,409 @@
+UNIT Unit6_imgfuncs;
+INTERFACE
+USES Math, Dialogs, SysUtils, Unit3_data, Unit15_Classes;
+
+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; VAR faded:Tdata):Boolean;
+
+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*(imgdepth DIV 8))+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
+    OniDataConnection.LoadDatFilePart(fileid,$10,SizeOf(Result.imgx),@Result.imgx);
+    OniDataConnection.LoadDatFilePart(fileid,$12,SizeOf(Result.imgy),@Result.imgy);
+    OniDataConnection.LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    OniDataConnection.LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    SetLength(images_decoded,linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      OniDataConnection.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;
+  VAR
+    img_addr:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$8C,SizeOf(Result.imgx),@Result.imgx);
+    OniDataConnection.LoadDatFilePart(fileid,$8E,SizeOf(Result.imgy),@Result.imgy);
+    OniDataConnection.LoadDatFilePart(fileid,$90,SizeOf(Result.storetype),@Result.storetype);
+    IF NOT OniDataConnection.OSisMac THEN
+      OniDataConnection.LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr)
+    ELSE
+      OniDataConnection.LoadDatFilePart(fileid,$A0,SizeOf(img_addr),@img_addr);
+
+    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);
+
+    IF NOT OniDataConnection.OSisMac THEN
+      OniDataConnection.LoadRawFile(fileid,$9C,@Result.imgdata[0])
+    ELSE
+      OniDataConnection.LoadRawFile(fileid,$A0,@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; VAR faded:Tdata):Boolean;
+  VAR
+    i:LongWord;
+    x,y:Word;
+    imgdata:Tdata;
+    fadelvldata:Tdata;
+  BEGIN
+    Result:=False;
+    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,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) OR ((x MOD 2)=1) OR ((y MOD 2)=1);
+    IF (x>1) AND (y>1) THEN Exit;
+    Result:=True;
+    SetLength(faded, Length(imgdata));
+    FOR i:=0 TO Length(imgdata)-1 DO faded[i]:=imgdata[i];
+  END;
+
+END.
Index: /oup/releases/0.31a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -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 = 'MIP Mapping'
+      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.31a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.31a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,224 @@
+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
+    actual_bmpdata:Tdata;
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit6_imgfuncs, Unit15_Classes;
+{$R *.dfm}
+
+PROCEDURE TForm7.Recreatelist;
+  VAR
+    files:TStringArray;
+    i:LongWord;
+  BEGIN
+    list_txmp.Items.Clear;
+    files:=OniDataConnection.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:=OniDataConnection.ExtractFileID(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+
+    OniDataConnection.LoadDatFilePart(id,$88,SizeOf(fadingbyte),@fadingbyte);
+    OniDataConnection.LoadDatFilePart(id,$89,SizeOf(depthbyte),@depthbyte);
+    OniDataConnection.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;
+    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:=OniDataConnection.ExtractFileID(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+      OniDataConnection.LoadDatFilePart(id,$8C,2,@oldwidth);
+      OniDataConnection.LoadDatFilePart(id,$8E,2,@oldheight);
+      OniDataConnection.LoadDatFilePart(id,$88,1,@oldfading);
+      OniDataConnection.LoadDatFilePart(id,$89,1,@olddepth);
+      OniDataConnection.LoadDatFilePart(id,$90,1,@oldstore);
+      OniDataConnection.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;
+
+      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_fading.Checked THEN
+        IF Not CreateFadedImage(imgpkg,imgpkg.imgdata) THEN
+          IF MessageBox(Self.Handle, PChar('Can not create a MipMapped-image (probably because of a wrong dimension).'+#13+#10+'Do you want to continue without MipMapping?'), PChar('Warning'), MB_YESNO)=ID_YES THEN
+            check_fading.Checked:=False
+          ELSE
+            Exit;
+
+      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) AND (OniDataConnection.Backend=ODB_Dat) THEN
+        new_rawaddr:=OniDataConnection.AppendRawFile(False,Length(imgpkg.imgdata),imgpkg.imgdata)
+      ELSE BEGIN
+        new_rawaddr:=old_rawaddr;
+        OniDataConnection.UpdateRawFile(id,$9C,Length(imgpkg.imgdata),imgpkg.imgdata); 
+      END;
+
+      datbyte:=$00;
+      IF check_fading.Checked THEN datbyte:=datbyte OR $01;
+      OniDataConnection.UpdateDatFilePart(id,$88,1,@datbyte);
+      datbyte:=$10;
+      IF check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      OniDataConnection.UpdateDatFilePart(id,$89,1,@datbyte);
+      OniDataConnection.UpdateDatFilePart(id,$8C,2,@imgpkg.imgx);
+      OniDataConnection.UpdateDatFilePart(id,$8E,2,@imgpkg.imgy);
+      IF check_32bit.Checked THEN
+        datbyte:=$08
+      ELSE
+        datbyte:=$01;
+      OniDataConnection.UpdateDatFilePart(id,$90,1,@datbyte);
+      OniDataConnection.UpdateDatFilePart(id,$9C,4,@new_rawaddr);
+
+      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(OniDataConnection.ExtractFileID(list_txmp.Items.Strings[list_txmp.ItemIndex]));
+      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.31a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.31a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.31a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,385 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 555
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 555
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+    ExplicitHeight = 423
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 555
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    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 = 450
+      Width = 483
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitTop = 375
+    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 = []
+      OnKeyUp = hexKeyUp
+      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 value_viewer: TWrapGrid
+      Left = 0
+      Top = 218
+      Width = 483
+      Height = 232
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      PopupMenu = value_viewer_context
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+    object VST: TVirtualStringTree
+      Left = 0
+      Top = 458
+      Width = 483
+      Height = 97
+      Align = alBottom
+      AnimationDuration = 0
+      AutoExpandDelay = 300
+      BiDiMode = bdLeftToRight
+      Colors.UnfocusedSelectionColor = clGradientActiveCaption
+      Colors.UnfocusedSelectionBorderColor = clGradientActiveCaption
+      Ctl3D = True
+      DragOperations = []
+      DrawSelectionMode = smBlendedRectangle
+      EditDelay = 200
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      Header.AutoSizeIndex = 0
+      Header.Font.Charset = DEFAULT_CHARSET
+      Header.Font.Color = clWindowText
+      Header.Font.Height = -11
+      Header.Font.Name = 'Tahoma'
+      Header.Font.Style = []
+      Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoVisible]
+      Header.PopupMenu = VTHPopup
+      Header.Style = hsFlatButtons
+      HintAnimation = hatNone
+      HintMode = hmTooltip
+      Indent = 14
+      ParentBiDiMode = False
+      ParentCtl3D = False
+      ParentFont = False
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 2
+      TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning]
+      TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowRoot, toShowTreeLines, toShowVertGridLines, toUseBlendedImages]
+      TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect]
+      OnDblClick = VSTDblClick
+      OnFocusChanged = VSTFocusChanged
+      OnGetText = VSTGetText
+      OnHeaderDragged = VSTHeaderDragged
+      Columns = <
+        item
+          MaxWidth = 300
+          MinWidth = 100
+          Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 0
+          Spacing = 20
+          Width = 150
+          WideText = 'Name'
+          WideHint = 'Name of the item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 1
+          Spacing = 20
+          Width = 85
+          WideText = 'Offset'
+          WideHint = 'Offset of the data-item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 75
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 2
+          Width = 75
+          WideText = 'Type'
+          WideHint = 'Data type of the item.'
+        end
+        item
+          MaxWidth = 250
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 3
+          Width = 100
+          WideText = 'Value'
+          WideHint = 'Value of the item.'
+        end
+        item
+          MaxWidth = 400
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 4
+          Width = 400
+          WideText = 'Description'
+        end>
+      WideDefaultText = ''
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 555
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Bevel1: TBevel
+      Left = 0
+      Top = 491
+      Width = 150
+      Height = 6
+      Align = alBottom
+      Style = bsRaised
+      ExplicitTop = 359
+    end
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 388
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 388
+      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 = 497
+      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
+  object VTHPopup: TVTHeaderPopupMenu
+    OnColumnChange = VTHPopupColumnChange
+    Left = 200
+    Top = 496
+  end
+end
Index: /oup/releases/0.31a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.31a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,887 @@
+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, Unit15_Classes,
+  Menus, Math, VirtualTrees, VTHeaderPopup;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    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;
+    VST: TVirtualStringTree;
+    VTHPopup: TVTHeaderPopupMenu;
+    procedure VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex);
+    procedure VSTDblClick(Sender: TObject);
+    procedure VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+      const Column: TColumnIndex; Visible: Boolean);
+    procedure VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+      OldPosition: Integer);
+    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE LoadDat(_fileid:LongWord);
+    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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    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 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
+    fileid:LongWord;
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit, Unit13_rawedit;
+
+TYPE
+  PNodeData = ^TNodeData;
+  TNodeData = record
+    Caption:String;
+    Offset:LongInt;
+    DataType:Word;
+    Value:String;
+    Description:String;
+  end;
+
+
+function AddVSTEntry(AVST:TCustomVirtualStringTree; ANode:PVirtualNode; ARecord:TNodeData):PVirtualNode;
+  var
+    data:PNodeData;
+  begin
+    Result:=AVST.AddChild(ANode);
+    data:=AVST.GetNodeData(Result);
+    AVST.ValidateNode(Result,False);
+    data^:=ARecord;
+  end;
+
+
+
+PROCEDURE TForm8.LoadDat(_fileid:LongWord);
+  VAR
+    i:LongWord;
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF OniDataConnection.ExtractFileID(list.Items.Strings[i])=fileid THEN BEGIN
+            list.ItemIndex:=i;
+            Exit;
+          END;
+        END;
+      END;
+    END;
+    fileid:=_fileid;
+    FOR i:=0 TO list.Count-1 DO
+      IF OniDataConnection.ExtractFileID(list.Items.Strings[i])=fileid THEN BEGIN
+        list.ItemIndex:=i;
+        Break;
+      END;
+    Self.ClearStructViewer;
+    data:=OniDataConnection.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; 
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.listClick(Sender: TObject);
+  BEGIN
+    LoadDat(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]));
+  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]);
+      11: Result:='0x'+IntToHex(OniDataConnection.GetRawInfo(fileid,offset).raw_addr,8);
+      12: Result:=FormatNumber(hex.data[offset+1]+hex.data[offset+2]*256+hex.data[offset+3]*256*256,5,'0');
+      13: Result:=IntToStr(hex.data[offset]);
+      14: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256);
+      15: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256);
+      16: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256);
+      100..300: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-100 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Break;
+          END;
+        END;
+      1000..9999: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-1000 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Result:=Result+'.';
+          END;
+        END;
+      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;
+  VAR
+    i,j:LongWord;
+    pdata: PNodeData;
+    data: TNodeData;
+    node: PVirtualNode;
+    structs: TStructDef;
+  BEGIN
+    VST.BeginUpdate;
+    IF VST.RootNodeCount=0 THEN BEGIN
+      structs:=LoadStructureDefinition(fileid);
+      IF structs.data THEN BEGIN
+        IF Length(structs.Global)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Global) DO BEGIN
+            data.Caption:=structs.Global[i].name;
+            data.Offset:=structs.Global[i].offset;
+            data.DataType:=structs.Global[i].datatype;
+            data.Value:=GetValue(structs.Global[i].datatype, structs.Global[i].offset);
+            data.Description:=structs.Global[i].description;
+            AddVSTEntry(VST, nil, data);
+          END;
+        END;
+        IF Length(structs.Subs)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Subs) DO BEGIN
+            WITH structs.Subs[i] DO BEGIN
+              IF Length(Entries)>0 THEN BEGIN
+                IF Pos('#',SubName)>0 THEN BEGIN
+                  data.Offset:=HexToLong(MidStr(SubName, Pos('#',SubName)+1, 8));
+                  data.Value:=MidStr(SubName, PosEx('#',SubName,Pos('#',SubName)+1)+1, 8);
+                  data.Caption:=MidStr(SubName, 1, Pos('#',SubName)-1);
+                  data.Description:=SubDesc;
+                END ELSE BEGIN
+                  data.Caption:=SubName;
+                  data.Description:=SubDesc;
+                  data.Offset:=0;
+                  data.Value:='';
+                END;
+                data.DataType:=0;
+                node:=AddVSTEntry(VST, nil, data);
+                data.Description:='';
+                FOR j:=0 TO High(Entries) DO BEGIN
+                  data.Caption:=Entries[j].name;
+                  data.Offset:=Entries[j].offset;
+                  data.DataType:=Entries[j].datatype;
+                  data.Value:=GetValue(Entries[j].datatype, Entries[j].offset);
+                  data.Description:=Entries[j].description;
+                  AddVSTEntry(VST, node, data);
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      IF VST.RootNodeCount>0 THEN
+        VST.FocusedNode:=VST.GetFirst;
+    END ELSE BEGIN
+      Node:=VST.GetFirst;
+      WHILE Assigned(Node) DO BEGIN
+        pdata:=VST.GetNodeData(Node);
+        IF pdata.DataType>0 THEN
+          pdata.Value:=GetValue(pdata.Datatype, pdata.Offset);
+        Node:=VST.GetNext(Node);
+      END;
+    END;
+    VST.EndUpdate;
+  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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            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;
+    VST.NodeDataSize:=SizeOf(TNodeData);
+    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;
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+OniDataConnection.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;
+          OniDataConnection.UpdateDatFile(fileid,data);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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;
+  BEGIN
+    VST.Clear;
+  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.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos;
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm8.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm8.hexSelectionChanged(Sender: TObject);
+  VAR
+    selstart:Integer;
+    node:PVirtualNode;
+    pdata:PNodeData;
+  BEGIN
+    IF hex.DataSize>0 THEN BEGIN
+      WriteValues;
+      selstart:=hex.SelStart;
+      IF VST.RootNodeCount>0 THEN BEGIN
+        Node:=VST.GetFirst;
+        WHILE Assigned(Node) DO BEGIN
+          pdata:=VST.GetNodeData(Node);
+          IF pdata.DataType>0 THEN BEGIN
+            IF ((selstart-pdata.Offset)<GetTypeDataLength(pdata.DataType)) AND ((selstart-pdata.Offset)>=0) THEN BEGIN
+              VST.FocusedNode:=Node;
+              VST.Selected[Node]:=True;
+              Break;
+            END;
+          END;
+          Node:=VST.GetNext(Node);
+        END;
+      END;
+    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 (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(fileid).Extension+'|All files|*.*';
+    saved.DefaultExt:=OniDataConnection.GetFileInfo(fileid).Extension;
+    IF saved.Execute THEN BEGIN
+      ExportDatFile(fileid,saved.FileName);
+    END;
+  END;
+
+PROCEDURE TForm8.btn_importClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  BEGIN
+    opend.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(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
+    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.VSTDblClick(Sender: TObject);
+  var
+    node:PVirtualNode;
+    nodedata:PNodeData;
+    id:Integer;
+  begin
+    if VST.FocusedColumn=3 then begin
+      node:=VST.FocusedNode;
+      nodedata:=VST.GetNodeData(node);
+
+      if not (nodedata.datatype in [11,12]) and ((nodedata.DataType<100) or (nodedata.DataType>300)) then begin
+        Form12.MakeVarInput(nodedata.Caption,nodedata.offset,nodedata.datatype,nodedata.value,Self);
+      end else begin
+        if nodedata.DataType=11 then begin
+          if OniDataConnection.GetRawInfo(fileid,nodedata.offset).raw_size>0 then begin
+            if Form1.open_child('rawedit') then begin
+              TForm13(Form1.ActiveMDIChild).LoadRaw(OniDataConnection.GetRawInfo(fileid,nodedata.offset));
+            end;
+          end;
+        end;
+        if nodedata.DataType=12 then begin
+          if (StrToInt(nodedata.Value)<OniDataConnection.GetFilesCount) and
+              (StrToInt(nodedata.Value)>0) and
+              (StrToInt(nodedata.Value)<>fileid) then begin
+            if OniDataConnection.GetFileInfo(StrToInt(nodedata.Value)).Size>0 then begin
+              if Form1.open_child('binedit') then begin
+                TForm8(Form1.ActiveMDIChild).LoadDat(StrToInt(nodedata.Value));
+              end;
+            end else begin
+              ShowMessage('Linked filed is a zero-byte-file');
+            end;
+          end;
+        end;
+        if (nodedata.DataType>=100) and (nodedata.DataType<=300) then begin
+          if Form1.open_child('binedit') then begin
+            TForm8(Form1.ActiveMDIChild).edit_filtername.Text:=nodedata.Value;
+            TForm8(Form1.ActiveMDIChild).check_filtername.Checked:=True;
+            TForm8(Form1.ActiveMDIChild).check_filternameClick(Self);
+          end;
+        end;
+      end;
+
+    end;
+  end;
+
+procedure TForm8.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex);
+  var
+    data:PNodeData;
+  begin
+    data:=VST.GetNodeData(node);
+    IF data.DataType>0 THEN BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+GetTypeDataLength(data.DataType)-1;
+    END ELSE BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+HexToLong(data.Value)-1;
+    END;
+  end;
+
+procedure TForm8.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+  var
+    data:PNodeData;
+  begin
+    data := Sender.GetNodeData(Node);
+    CellText := '';
+    if TextType = ttNormal then begin
+      case Column of
+        0: CellText := data.Caption;
+        1:
+          if data.DataType>0 then
+            CellText := '0x'+IntToHex(data.Offset,8)
+          else
+            if data.Offset>0 then
+              CellText := '0x'+IntToHex(data.Offset,8);
+        2:
+          if data.DataType>0 then
+            CellText := GetDataType(data.DataType);
+        3:
+          if data.DataType>0 then
+            CellText := data.Value //GetValue(data.DataType, data.Offset)
+          else
+            if Length(data.Value)>0 then
+              CellText := IntToStr(HexToLong(data.Value))+' Bytes';
+        4:
+          CellText := data.Description;
+      end;
+    end;
+  end;
+
+procedure TForm8.VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+  OldPosition: Integer);
+  begin
+    if Sender.Columns.Items[column].Position<1 then
+      Sender.Columns.Items[column].Position:=OldPosition;
+  end;
+
+procedure TForm8.VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+  const Column: TColumnIndex; Visible: Boolean);
+  begin
+    if column=0 then
+      TVirtualStringTree(Sender).Header.Columns.Items[column].Options:=TVirtualStringTree(Sender).Header.Columns.Items[column].Options+[coVisible];
+  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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+
+END.
Index: /oup/releases/0.31a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.31a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.31a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,458 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, Classes, Unit3_data, Dialogs, StrUtils;
+
+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
+                      // 11    : raw-addr
+                      // 12    : dat-file-ID
+                      // 13..16: Signed Integer[1..4]
+                      // 100..300: dat-file-name[0..200]
+                      // 1000..9999: Unused data[0-8999]
+                      // 10000+: string[0+]
+      description:String;
+    END;
+  TStructDefSub=RECORD
+      SubName:String;
+      SubDesc:String;
+      Entries:Array OF TStructure_entry;
+    END;
+  TStructDef=RECORD
+      Data:Boolean;
+      Global:Array OF TStructure_entry;
+      Subs:Array OF TStructDefSub;
+    END;
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+
+VAR
+  RawListHandlers:Array OF TRawListHandlers;
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+
+IMPLEMENTATION
+USES Unit2_functions, Unit15_Classes, Forms;
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      12: Result:=4;
+      13..16: Result:=datatype-12;
+      100..300: Result:=datatype-100;
+      1000..9999: Result:=datatype-1000;
+      10000..65535: Result:=datatype-10000;
+    END;
+  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';
+      11: Result:='Raw-Address';
+      12: Result:='.dat-file-ID';
+      13..16: Result:='SignedInt'+IntToStr((typeid-12)*8);
+      100..300: Result:='.dat-file-name('+IntToStr(typeid-100)+')';
+      1000..9999: Result:='Unused('+IntToStr(typeid-1000)+')';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT OniDataConnection.OSisMac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*4;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*4,4,@link);
+        Result[i].raw_addr:=link;
+        Result[i].raw_size:=0{????????????????????????????????};
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION AKVA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT OniDataConnection.OSisMac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*$74+$24;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*$74+$24,4,@link);
+        Result[i].raw_addr:=link;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*$74+$28,4,@link);
+        Result[i].raw_size:=link;
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    OniDataConnection.LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=OniDataConnection.OSisMac;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$08,4,@datasize);
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=OniDataConnection.OSisMac;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    SetLength(Result,1);
+    IF NOT OniDataConnection.OSisMac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$40,4,@datasize);
+      OniDataConnection.LoadDatFilePart(fileid,$44,4,@link);
+      Result[0].src_offset:=$44;
+    END ELSE BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$10,4,@datasize);
+      OniDataConnection.LoadDatFilePart(fileid,$14,4,@link);
+      Result[0].src_offset:=$14;
+    END;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=False;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,lastlink:LongWord;
+    links:LongWord;
+    i,j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$18,4,@baselink);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$20+(links-1)*4,4,@lastlink);
+      SetLength(data,lastlink+1024);
+        TOniDataDat(OniDataConnection).LoadRawOffset(false, baselink,lastlink+1024,data); 
+//      OniDataConnection.LoadRawFile(fileid,$1C,baselink,lastlink+1024,False,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[lastlink+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=lastlink+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Byte;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+  BEGIN
+    SetLength(Result,13);
+    OniDataConnection.LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    OniDataConnection.LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    OniDataConnection.LoadDatFilePart(fileid,$182,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    OniDataConnection.LoadDatFilePart(fileid,$183,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    OniDataConnection.LoadDatFilePart(fileid,$184,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    OniDataConnection.LoadDatFilePart(fileid,$185,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    OniDataConnection.LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    OniDataConnection.LoadDatFilePart(fileid,$186,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    OniDataConnection.LoadDatFilePart(fileid,$187,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    OniDataConnection.LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    OniDataConnection.LoadDatFilePart(fileid,$154,2,@tempw);
+    OniDataConnection.LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    OniDataConnection.LoadDatFilePart(fileid,$138,4,@templ);
+    OniDataConnection.LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    OniDataConnection.LoadDatFilePart(fileid,$34,4,@link);
+    tempw:=0;
+    IF link>0 THEN BEGIN
+      {BODY ANIMATIONS PART DECODE!!!}
+      SetLength(data,$FFFF);
+      TOniDataDat(OniDataConnection).LoadRawOffset(false,link,$FFFF,data); 
+//      OniDataConnection.LoadRawFile(fileid,$34,link,$FFFF,False,@data[0]);
+      offset:=data[24]+data[25]*255;
+      {}
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+    Result[10].raw_size:=tempw;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link_pc:LongWord;
+    link_mac:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    OniDataConnection.LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    OniDataConnection.LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    OniDataConnection.LoadDatFilePart(fileid,$9C,4,@link_pc);
+    OniDataConnection.LoadDatFilePart(fileid,$A0,4,@link_mac);
+    CASE storetype OF
+      0,1,2: datasize:=x*y*2;
+      8: datasize:=x*y*4;
+      9: datasize:=x*y DIV 2;
+    END;
+    SetLength(Result,1);
+    IF NOT OniDataConnection.OSisMac THEN BEGIN
+      Result[0].src_offset:=$9C;
+      Result[0].raw_addr:=link_pc
+    END ELSE BEGIN
+      Result[0].src_offset:=$A0;
+      Result[0].raw_addr:=link_mac;
+    END;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=OniDataConnection.OSisMac;
+  END;
+
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+  END;
+
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+  VAR
+    i:LongWord;
+    current_type:Byte; //0: Global, 1: Undynamic, 2: Dynamic
+    current_base,current_package,current_package_size:LongWord;
+    packages:LongWord;
+    deffile:Text;
+    structentry:TStructure_Entry;
+    fields:TStringArray;
+    filename:String;
+    ext:String[4];
+    temps:String;
+    data:TData;
+  BEGIN
+    SetLength(Result.Global,0);
+    SetLength(Result.Subs,0);
+    Result.Data:=False;
+    ext:=OniDataConnection.GetFileInfo(fileid).Extension;
+    filename:=ExtractFilePath(Application.ExeName)+'\StructDefs\'+ext+'.txt';
+    IF FileExists(filename) THEN BEGIN
+      data:=OniDataConnection.LoadDatFile(fileid);
+      AssignFile(deffile,filename);
+      Reset(deffile);
+      current_type:=0;
+      Result.Data:=True;
+      IF NOT EoF(deffile) THEN BEGIN
+        ReadLn(deffile,temps);
+        WHILE NOT EoF(deffile) DO BEGIN
+          ReadLn(deffile,temps);
+          IF (Length(temps)>0) AND (temps[1]<>'#') THEN BEGIN
+            IF temps[1]='*' THEN BEGIN
+              fields:=Explode(temps,#9);
+              CASE Length(fields) OF
+                1..2: BEGIN
+                     current_type:=1;
+                     current_base:=0;
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                     IF Length(fields)=2 THEN
+                       Result.Subs[High(Result.Subs)].SubDesc:=fields[1];
+                   END;
+                3: BEGIN
+                     current_type:=1;
+                     current_base:=HexToLong(fields[2]);
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                     Result.Subs[High(Result.Subs)].SubDesc:=fields[1];
+                   END;
+                6: BEGIN
+                     current_type:=2;
+                     current_base:=HexToLong(fields[2]);
+                     current_package:=0;
+                     current_package_size:=StrToInt(fields[5]);
+                     IF fields[4][1]<>'$' THEN BEGIN
+                       CASE StrToInt(fields[4]) OF
+                         1: packages:=data[HexToLong(fields[3])];
+                         2: packages:=data[HexToLong(fields[3])]+data[HexToLong(fields[3])+1]*256;
+                         4: packages:=data[HexToLong(fields[3])]+data[HexToLong(fields[3])+1]*256+data[HexToLong(fields[3])+2]*256*256+data[HexToLong(fields[3])+3]*256*256*256;
+                       END;
+                     END ELSE BEGIN
+                       packages:=HexToLong(fields[4]);
+                     END;
+                     SetLength(Result.Subs, Length(Result.Subs)+packages);
+                     FOR current_package:=0 TO packages-1 DO BEGIN
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubName:=
+                           MidStr(fields[0],2,Length(fields[0])-1)+'['+IntToStr(current_package)+']'+
+                           '#'+IntToHex(current_base+current_package*current_package_size,8)+
+                           '#'+IntToHex(current_package_size,8);
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubDesc:=
+                           fields[1];
+                     END;
+                   END;
+              END;
+            END ELSE BEGIN
+              fields:=Explode(temps,#9);
+              IF (Length(fields)=3) OR (Length(fields)=4) THEN BEGIN
+                structentry.name:=fields[0];
+                structentry.datatype:=StrToInt(fields[2]);
+                IF Length(fields)=4 THEN
+                  structentry.description:=fields[3]
+                ELSE
+                  structentry.description:='';
+                IF current_type IN [0,1] THEN BEGIN
+                  structentry.offset:=HexToLong(fields[1])+current_base;
+                  IF Length(Result.Subs)=0 THEN BEGIN
+                    SetLength(Result.Global,Length(Result.Global)+1);
+                    Result.Global[High(Result.Global)]:=structentry;
+                  END ELSE BEGIN
+                    SetLength(Result.Subs[High(Result.Subs)].Entries,Length(Result.Subs[High(Result.Subs)].Entries)+1);
+                    Result.Subs[High(Result.Subs)].Entries[High(Result.Subs[High(Result.Subs)].Entries)]:=structentry;
+                  END;
+                END ELSE BEGIN
+                  FOR current_package:=0 TO packages-1 DO BEGIN
+                    structentry.offset:=current_base+current_package*current_package_size+HexToLong(fields[1]);
+                    WITH Result.Subs[High(Result.Subs)-packages+current_package+1] DO BEGIN
+                      SetLength(Entries,Length(Entries)+1);
+                      Entries[High(Entries)]:=structentry;
+                    END;
+                  END;
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      CloseFile(deffile);
+    END;
+  END;
+
+
+BEGIN
+//  InsertRawListHandler('AGDB',True,AGDB);
+  InsertRawListHandler('AKVA',True,AKVA);
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.31a/todo.txt
===================================================================
--- /oup/releases/0.31a/todo.txt	(revision 8)
+++ /oup/releases/0.31a/todo.txt	(revision 8)
@@ -0,0 +1,159 @@
+Unit10 unabhängig, funktionsweise wiederherstellen
+Schreibt auch die dat_files[] etc
+Benutzt die *globalen* dat_stream/raw_stream und keine MemCopy
+
+
+-Hex: Paste
+
+-Datei von einem Tool in andrem Tool öffnen
+
+-TXMPReplace: Zugriff über Unit2
+
+
+-SELECT [src_id],MIN(datfiles.[name]),SUM(rawmap.[size]) FROM rawmap INNER  JOIN datfiles ON datfiles.[id]=[src_id] GROUP BY [src_id] ORDER BY [src_id] ASC
+
+-Extrahier-Ordner-Option (mit Platzhalter für .dat-Name)
+
+-HELP.hlp
+-About
+
+-BinEdit: Zusatzfunktionen wie: Suche, 
+-BinEdit: Bild/Menu/Button irgendwas zum speichern
+
+-Extractor: Wohin?
+
+-FileCompare: Ergebnis=Tabelle, jede Zeile eine differenz-addresse, spalten = werte an addr. für compared files
+
+-TXMP-Replace: MultiReplace
+
+-Move-Freischalter (Mindestlvl eingabe)
+
+-Löschen einer Datei auf die gelinkt wird: Liste der Links und sicherheitsfrage
+
+-Filebox-Context: Extract etc
+
+-DAT geladen -> Meldung oder sogar "what to do next?"
+-SSG: Levels extrahieren?
+-Pierre: Wie Char-Anims, Char-Models, Levels extrahieren?
+-Language-Files?
+-STRG+C auf Dateilisten etc für kopieren des Namens
+
+-REPACKING: testen lvl0: 690-collisions.txmp einbauen, script: collisions-zeug
+
+#################################################################
+##########                 File-Types                  ##########
+#################################################################
+(3CLA)
+ABNA
+AGDB
+AGQC
+AGQG
+(AGQM)
+AGQR
+AISA
+AITR
+(AIWA)
+AKAA
+AKBA
+AKBP
+AKDA
+AKEV
+AKOT
+AKVA
+BINA
+CBPI
+CBPM
+CONS
+CRSA
+DOOR
+DPge
+(EDIA)
+ENVP
+FILM
+(FXLR)
+(GMAN)
+HPge
+IDXA
+IGHH
+IGPA
+IGPG
+IGSA
+IGSt
+Impt
+IPge
+KeyI
+M3GA
+M3GM
+(M3TA)
+Mtrl
+(NMSA)
+OBAN
+OBDC
+(OBLS)
+OBOA
+OFGA
+ONCC
+ONCP
+ONCV
+ONFA
+ONGS
+ONIA
+ONLD
+ONLV
+ONMA
+ONOA
+ONSA
+ONSK
+ONTA
+ONVL
+ONWC
+OPge
+OSBD
+OTIT
+OTLF
+PLEA
+PNTA
+PSpc
+PSpL
+PSUI
+QTNA
+(QUDA)
+SNDD
+StNA
+SUBT
+(TMFA)
+(TMRA)
+TRAC
+TRAM
+TRAS
+TRBS
+TRCM
+(TRFT)
+TRGA
+TRGE
+TRIA
+TRIG
+TRMA
+TRSC
+TRTA
+TSFF
+TSFL
+TSFT
+TSGA
+TStr
+TURR
+TXAN
+TXCA
+TXMA
+TXMB
+TXMP
+(TXPC)
+TxtC
+(UUEA)
+(UVDL)
+VCRA
+WMCL
+WMDD
+WMM_
+WMMB
+WPge
Index: /oup/releases/0.32a/StructDefs/AISA.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/AISA.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/AISA.txt	(revision 8)
@@ -0,0 +1,10 @@
+AI Character Setup Array
+
+File ID	$00	12
+Level ID	$04	4
+Unused	$08	1022
+Packages	$1E	2
+
+*AIs		$20	$1E	2	352
+ONCC-Linkk	$28	12
+Intro func	$50	10032
Index: /oup/releases/0.32a/StructDefs/DOOR.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/DOOR.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/DOOR.txt	(revision 8)
@@ -0,0 +1,2 @@
+DOOR File
+Open sound	$24	132	Test
Index: /oup/releases/0.32a/StructDefs/ONCC.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/ONCC.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/ONCC.txt	(revision 8)
@@ -0,0 +1,58 @@
+Oni character class
+TXMP link	$28	12	Shadow texture
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use an hypo
+Hurt light sound	$98	10032	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	10032	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	10032	Reference to an OSBD file of level 0
+Death sound	$F8	10032	Reference to an OSBD file of level 0
+Taunt sound query	$2B0	10	00 = not used; 64 = used
+"Whos there?" sound query	$2B1	10	00 = not used; 64 = used
+"I see you" sound query	$2B2	10	00 = not used; 64 = used
+"You lose" sound query	$2B3	10	00 = not used; 64 = used
+"Where are you?" sound query	$2B4	10	00 = not used; 64 = used
+"Why is this happenung?" sound query	$2B5	10	00 = not used; 64 = used
+Superpunch sound query	$2B6	10	00 = not used; 64 = used
+Superkick sound query	$2B7	10	00 = not used; 64 = used
+Super3 sound query	$2B8	10	00 = not used; 64 = used
+Super4 sound query	$2B9	10	00 = not used; 64 = used
+Taunt sound	$2BC	10032	Reference to a SNDD file of level 0
+"Whos there?" sound	$2DC	10032	Reference to a SNDD file of level 0
+"I see you" sound	$2FC	10032	Reference to a SNDD file of level 0
+"You lose" sound	$31C	10032	Reference to a SNDD file of level 0
+"Where are you?" sound	$33C	10032	Reference to a SNDD file of level 0
+"Why is this happenung?" sound	$35C	10032	Reference to a SNDD file of level 0
+Superpunch sound	$37C	10032	Reference to a SNDD file of level 0
+Superkick sound	$39C	10032	Reference to a SNDD file of level 0
+Super3 sound	$3BC	10032	Reference to a SNDD file of level 0
+Super4 sound	$3DC	10032	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV link	$434	12	Character varient link
+ONCP link	$438	12	Character particle array link; useless?
+ONIA link	$43C	12	Character impact array link; useless?
+Unknown	$444	10016	Maybe the weight of the character?
+Footstep walk impact	$454	10128	Reference to the a Impt file of level 0
+Footstep run impact	$4D6	10128	Reference to the a Impt file of level 0
+Footstep crouch impact	$558	10128	Reference to the a Impt file of level 0
+Fall slide impact	$5DA	10128	Reference to the a Impt file of level 0
+Fall land impact	$65C	10128	Reference to the a Impt file of level 0
+Fall land hard impact	$6DE	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$760	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$7E2	10128	Reference to the a Impt file of level 0
+Fall knockdown impact	$864	10128	Reference to the a Impt file of level 0
+Footstep turn impact	$8E6	10128	Reference to the a Impt file of level 0
+Footstep run start impact	$968	10128	Reference to the a Impt file of level 0
+Footstep single step impact	$9EA	10128	Reference to the a Impt file of level 0
+Footstep run stop impact	$A6C	10128	Reference to the a Impt file of level 0
+Footstep walk stop impact	$AEE	10128	Reference to the a Impt file of level 0
+Footstep run sprint impact	$B70	10128	Reference to the a Impt file of level 0
+Unknown	$BF4	10064	special death particles; only the mad bomber use it
+TRBS link	$C3C	8	Body set link
+TRMA link	$C40	8	Texture map array link
+CBPM link	$C44	8	Body part material link
+CBPI link	$C48	8	Body part impact link
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC link	$C88	8	Animation collection link
+TRSC link	$C8C	8	Screen (aiming) collection link
Index: /oup/releases/0.32a/StructDefs/ONLD.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/ONLD.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/ONLD.txt	(revision 8)
@@ -0,0 +1,8 @@
+Oni Level Descriptor
+
+ID	$00	12	ID of this file
+LevelID	$04	8	ID of the level this file is in
+LevelID for this level	$08	2
+LevelID for next level	$0A	2
+LevelName	$0C	10064
+Unused	$4C	1020
Index: /oup/releases/0.32a/StructDefs/ONLV.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/ONLV.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/ONLV.txt	(revision 8)
@@ -0,0 +1,21 @@
+Oni Level Descriptor
+
+ID	$00	12	ID of this file
+LevelID	$04	17	ID of the level this file is in
+LevelName	$08	10064
+AKEV-Link	$48	12
+OBOA-Link	$4C	12
+ONMA-Link	$50	12
+ONFA-Link	$54	12
+ONTA-Link	$58	12
+ONSK-Link	$5C	12
+Unused?	$60	12
+AISA-Link	$64	12
+AITR-Link	$68	12
+ONSA-Link	$6C	12
+OBDC-Link	$70	12
+ENVP-Link	$74	12
+ENVP-Link	$78	12
+Unused	$7C	1644
+CRSA-Link	$300	12
+Unused	$304	1028
Index: /oup/releases/0.32a/StructDefs/SUBT.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/SUBT.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/SUBT.txt	(revision 8)
@@ -0,0 +1,5 @@
+Subtitles
+ID	$00	4	ID of this file
+LevelID	$04	8	ID of the level this file is in
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Subtitle count	$1C	4	Number of subtitles in this file
Index: /oup/releases/0.32a/StructDefs/TRAM.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/TRAM.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/TRAM.txt	(revision 8)
@@ -0,0 +1,49 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	8	Flags; It seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	8	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	8	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	8	Used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	2	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	116	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	6	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
Index: /oup/releases/0.32a/StructDefs/TXAN.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/TXAN.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/TXAN.txt	(revision 8)
@@ -0,0 +1,14 @@
+Texture Animation
+
+File ID	$00	12	File ID of this file
+Level Number	$04	4
+Unused	$08	1012
+
+Loop speed	$14	2
+Unknown	$16	2
+Unknown	$18	2
+Unused	$1A	1002
+Number of images	$1C	4
+
+*Packages		$20	$1C	4	4
+Image	$0	12
Index: /oup/releases/0.32a/StructDefs/TXMP.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/TXMP.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/TXMP.txt	(revision 8)
@@ -0,0 +1,13 @@
+Texture
+ID	$00	12	ID of this file
+LevelID	$04	8	ID of the level this file is in
+FileName	$08	10128	
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	12	Link to the TXAN-file (if this TXMP is the first image of an animation)
+TXMP-Link	$98	12	Link to another TXMP-file
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
Index: /oup/releases/0.32a/StructDefs/WMDD.txt
===================================================================
--- /oup/releases/0.32a/StructDefs/WMDD.txt	(revision 8)
+++ /oup/releases/0.32a/StructDefs/WMDD.txt	(revision 8)
@@ -0,0 +1,21 @@
+Window Menu Dialog Data
+
+File ID	$00	12
+Level ID	$04	4
+Title	$08	10256
+Ident value	$108	8
+Status	$10C	8
+Design	$110	10
+Design2	$111	1001	Unused?
+Position	$112	6
+Unknown	$114	8
+Width	$118	2
+Height	$11A	2
+Entries	$11C	4
+
+*Entry		$120	$11C	4	292
+Caption	$0	10256
+Type	$100	2
+Button link	$102	2
+Options	$104	2
+Unknown	$106	2
Index: /oup/releases/0.32a/blubb.txt
===================================================================
--- /oup/releases/0.32a/blubb.txt	(revision 8)
+++ /oup/releases/0.32a/blubb.txt	(revision 8)
@@ -0,0 +1,6 @@
+___FILEINDEX___.txt
+
+
+TXMP:
+MipMapping: Bit0=an/aus
+ColorDepth: Bit0=??AnimationPic??, Bit1=shade vertex, Bit2=transparency, Bit4=16bit, Bit5=32bit
Index: /oup/releases/0.32a/changelog.txt
===================================================================
--- /oup/releases/0.32a/changelog.txt	(revision 8)
+++ /oup/releases/0.32a/changelog.txt	(revision 8)
@@ -0,0 +1,109 @@
+OniUnPacker v0.32a
+------------------
++Raw-part "BodyPartAnimation data" of TRAMs
++Added basic DB2Dat functionality (SHOULD NOT BE USED YET!!!)
++CharSet selection (works for ValueViewer only right now)
+
+OniUnPacker v0.31a
+------------------
++Dat2DB function working
++Fixed a bug which appeared when multiple windows of the same class were opened at one time (eg 2*BinEdit)
+
+OniUnPacker v0.30a
+------------------
++Completely rewritten data-backend-connection-classes (Unit15_Classes.pas)
+
+OniUnPacker v0.29a
+------------------
++Little changes in StructureDefs
+
+OniUnPacker v0.29a
+------------------
++New StructureViewer
++New StructureTypes: 12=.dat-file-ID, 13..16=SignedInteger, 1000..9999=Unused data
++Dynamic Structures (look at TXAN-files or AISA-files for examples)
++File-type associations (.dat, .oldb, .opf) with OUP possible
++File IDs as Hex
+
+OniUnPacker v0.28a
+------------------
++StructureDefinitions as separate txt-files
++Minor bugfixes
++Ctrl+C for Hex-fields
+
+OniUnPacker v0.27a
+------------------
++Added MAC-file support
++Added StructureDefs for ONCCs / TRAMs (thanks to SSG)
+
+OniUnPacker v0.26a
+------------------
++Fixed some bugs again ;)
+
+OniUnPacker v0.25a
+------------------
++Fixed some bugs here and there ;)
++BinEdit/RawEdit: Added keycombo CTRL+S for saving current file
+
+OniUnPacker v0.24a
+------------------
++RawEdit. Open it by doubleclick on a Raw-Link in the StructureViewer of BinEdit or enter the FileID and the offset of the raw-link in the .dat-file manually
+
+OniUnPacker v0.23a
+------------------
++Added copy2clipboard functions to ValueViewer (rightclick)
++Enhanced FileList-filters
++Added ValueEditor to BinEdit -> StructViewer / ValueViewer (doubleclick on either value field of ValueViewer or StructViewer)
+
+OniUnPacker v0.22a
+------------------
++Replaced DB-Backend (much faster conversion of levels)
++Added ValueViewer to BinEdit (decodes selected area as different variable-types)
+
+OniUnPacker v0.21a
+------------------
++Extractor tool works almost completely (you can't select where the files are stored if you *don't* choose to put them all in one file. They are stored in the root of drive d:)
++Corrected string-display in the structure viewer of BinEdit (strings are now displayed as a hint of the value-box if you move the mouse over it)
+
+OniUnPacker v0.20a
+------------------
++? (Forgot what I added here ;) )
+
+OniUnPacker v0.19a
+------------------
++.dat/.raw -> OUP-Level-DB-Convert basics
++Extractor tool (not working yet :D )
+
+OniUnPacker v0.18a
+------------------
++Completely rewritten GUI
+
+OniUnPacker v0.17a
+------------------
++Binary-editor: Structure-viewer (only TXMP so far)
+
+OniUnPacker v0.16a
+------------------
++Replaced hex-view-box with a true hex-component
++Binary-editor for .dat-files
+
+OniUnPacker v0.15a
+------------------
++Extract menu
++Changed layout
+
+OniUnPacker v0.14a
+------------------
++Corrected image-decoder for 32bit images
++TXMP-Replace: 32bit option (for prevention from quality loss)
+
+OniUnPacker v0.13a
+------------------
++TXMP-Replace: Transparency option
++TXMP-Replace: Fading option
++TXMP-Replace: Overwrites old data if the new fits in that space (to keep the raw as small as possible)
+
+OniUnPacker v0.12a
+------------------
++TXMP-Replace function (Menu -> Tools -> TXMP Replacer)
++TXMB-Decoder (export with convert & preview)
Index: /oup/releases/0.32a/src/OniUnPacker.bdsproj
===================================================================
--- /oup/releases/0.32a/src/OniUnPacker.bdsproj	(revision 8)
+++ /oup/releases/0.32a/src/OniUnPacker.bdsproj	(revision 8)
@@ -0,0 +1,183 @@
+﻿<?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 Name="UnitInitSeq">True</Compiler>
+			<Compiler Name="LocalPInvoke">True</Compiler>
+			<Compiler Name="CodePage"></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 Name="GenerateHpps">False</Linker>
+		</Linker>
+		<Directories>
+			<Directories Name="OutputDir">exe</Directories>
+			<Directories Name="UnitOutputDir">dcu</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 Name="Debug Symbols Search Path"></Parameters>
+			<Parameters Name="LoadAllSymbols">True</Parameters>
+			<Parameters Name="LoadUnspecifiedSymbols">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>
+		<Language>
+			<Language Name="ActiveLang"></Language>
+			<Language Name="ProjectLang">$00000000</Language>
+			<Language Name="RootDir"></Language>
+		</Language>  <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.32a/src/OniUnPacker.cfg
===================================================================
--- /oup/releases/0.32a/src/OniUnPacker.cfg	(revision 8)
+++ /oup/releases/0.32a/src/OniUnPacker.cfg	(revision 8)
@@ -0,0 +1,40 @@
+-$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
+-E"exe"
+-N0"dcu"
+-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.32a/src/OniUnPacker.dpr
===================================================================
--- /oup/releases/0.32a/src/OniUnPacker.dpr	(revision 8)
+++ /oup/releases/0.32a/src/OniUnPacker.dpr	(revision 8)
@@ -0,0 +1,32 @@
+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},
+  Unit13_rawedit in 'Unit13_rawedit.pas' {Form13},
+  Unit14_settings in 'Unit14_settings.pas' {Form14},
+  ftypesAPI in 'TFileTypeRegistration\ftypesAPI.pas',
+  Unit15_Classes in 'Unit15_Classes.pas';
+
+{$R *.res}
+{$R icon2.res}
+
+BEGIN
+  Application.Initialize;
+  Application.Title:='Oni Un/Packer';
+  Application.CreateForm(TForm1, Form1);
+  Application.CreateForm(TForm10, Form10);
+  Application.CreateForm(TForm12, Form12);
+  Application.CreateForm(TForm14, Form14);
+  Application.Run;
+END.
Index: /oup/releases/0.32a/src/TFileTypeRegistration/IsAdmin.inc
===================================================================
--- /oup/releases/0.32a/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
+++ /oup/releases/0.32a/src/TFileTypeRegistration/IsAdmin.inc	(revision 8)
@@ -0,0 +1,90 @@
+function GetAdminSid: PSID;
+const
+  // bekannte SIDs ... (WinNT.h)
+  SECURITYNTAUTHORITY: TSIDIdentifierAuthority = (Value: (0, 0, 0, 0, 0, 5));
+  // bekannte RIDs ... (WinNT.h)
+  SECURITYBUILTINDOMAINRID: DWORD = $00000020;
+  DOMAINALIASRIDADMINS: DWORD = $00000220;
+begin
+  Result := nil;
+  AllocateAndInitializeSid(SECURITYNTAUTHORITY,
+    2,
+    SECURITYBUILTINDOMAINRID,
+    DOMAINALIASRIDADMINS,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    Result);
+end;
+
+function IsAdmin: LongBool;
+var
+  TokenHandle      : THandle;
+  ReturnLength     : DWORD;
+  TokenInformation : PTokenGroups;
+  AdminSid         : PSID;
+  Loop             : Integer;
+  wv               : TOSVersionInfo;
+begin
+  wv.dwOSVersionInfoSize := sizeof(TOSversionInfo);
+  GetVersionEx(wv);
+
+  Result := (wv.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS);
+
+  if(wv.dwPlatformId = VER_PLATFORM_WIN32_NT) then
+    begin
+      TokenHandle := 0;
+      if OpenProcessToken(GetCurrentProcess, TOKEN_QUERY, TokenHandle) then
+        try
+          ReturnLength := 0;
+          GetTokenInformation(TokenHandle, TokenGroups, nil, 0, ReturnLength);
+          TokenInformation := GetMemory(ReturnLength);
+          if Assigned(TokenInformation) then
+            try
+              if GetTokenInformation(TokenHandle, TokenGroups,
+                TokenInformation, ReturnLength, ReturnLength) then
+              begin
+                AdminSid := GetAdminSid;
+                for Loop := 0 to TokenInformation^.GroupCount - 1 do
+                  begin
+                    if EqualSid(TokenInformation^.Groups[Loop].Sid, AdminSid) then
+                      begin
+                        Result := True; break;
+                      end;
+                  end;
+                FreeSid(AdminSid);
+              end;
+            finally
+              FreeMemory(TokenInformation);
+            end;
+        finally
+          CloseHandle(TokenHandle);
+        end;
+    end;
+end;
+
+function WVersion: string; 
+var 
+  OSInfo: TOSVersionInfo; 
+begin 
+  Result := '3X'; 
+  OSInfo.dwOSVersionInfoSize := sizeof(TOSVERSIONINFO); 
+  GetVersionEx(OSInfo); 
+  case OSInfo.dwPlatformID of 
+    VER_PLATFORM_WIN32S: begin 
+        Result := '3X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_WINDOWS: begin 
+        Result := '9X'; 
+        Exit; 
+      end; 
+    VER_PLATFORM_WIN32_NT: begin 
+        Result := 'NT'; 
+        Exit; 
+      end; 
+  end; //case 
+end;
Index: /oup/releases/0.32a/src/TFileTypeRegistration/SysUtils.inc
===================================================================
--- /oup/releases/0.32a/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
+++ /oup/releases/0.32a/src/TFileTypeRegistration/SysUtils.inc	(revision 8)
@@ -0,0 +1,307 @@
+function fileexists(const szFilename: string): boolean;
+var
+  Handle   : THandle;
+  FindData : TWin32FindData;
+begin
+  Handle := FindFirstFile(pchar(szFilename),FindData);
+  Result := (Handle <> INVALID_HANDLE_VALUE);
+
+  if(Result) then Windows.FindClose(Handle);
+end;
+
+function ExtractFileDrive(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') then
+    begin
+      Result := copy(szFilename,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFilePath(const szFilename: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+  i      := length(szFileName);
+  while(i > 0) do
+  begin
+    if(szFileName[i] = ':') or
+      (szFileName[i] = '\') then
+    begin
+      Result := copy(szFileName,1,i);
+      break;
+    end;
+
+    dec(i);
+  end;
+end;
+
+function ExtractFileName(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '\') then
+      break;
+
+    dec(i);
+  end;
+
+  Result := copy(szFilename,i + 1,length(szFilename));
+end;
+
+function CutFileExt(const szFilename: string): string;
+var
+  i : integer;
+begin
+  i := length(szFilename);
+  while(i > 0) do
+  begin
+    if(szFilename[i] = '.') then
+      break;
+
+    dec(i);
+  end;
+
+  if(i = 0) then Result := szFilename
+    else Result := copy(szFilename,1,i-1);
+end;
+
+function ChangeFileExt(const szFileName, szNewExt: string): string;
+begin
+  Result := CutFileExt(szFileName);
+
+  if(szNewExt[1] <> '.') then Result := Result + '.' + szNewExt
+    else Result := Result + szNewExt;
+end;
+
+function FileSearch(const Name, DirList: string): string;
+var
+  I, P, L: Integer;
+begin
+  Result := Name;
+  P      := 1;
+  L      := length(DirList);
+
+  while(true) do begin
+    if(fileexists(Result)) then exit;
+
+    while(P <= L) and (DirList[P] = ';') do inc(P);
+    if(P > L) then break;
+
+    I := P;
+    while(P <= L) and (DirList[P] <> ';') do inc(P);
+
+    Result   := copy(DirList,I,P-I);
+    if not(Result[length(Result)] in[':','\']) then
+      Result := Result + '\';
+
+    Result := Result + Name;
+  end;
+
+  Result  := '';
+end;
+
+function StrToIntDef(const s: string; const i: integer): integer;
+var
+  code : integer;
+begin
+  Val(s,Result,code); if(code <> 0) then
+                        Result := i;
+end;
+
+function IntToStr(const i: integer): string;
+begin
+  Str(i,Result);
+end;
+
+// -----------------------------------------------------------------------------
+
+function Format(fmt: string; params: array of const): string;
+var
+  pdw1,
+  pdw2 : PDWORD;
+  i    : integer;
+  pc   : PCHAR;
+begin
+  pdw1 := nil;
+
+  if High(params) >= 0 then
+    GetMem(pdw1, (High(params) + 1) * sizeof(Pointer));
+
+  pdw2  := pdw1;
+  for i := 0 to High(params) do
+    begin
+      pdw2^ := PDWORD(@params[i])^;
+      inc(pdw2);
+    end;
+
+  pc := GetMemory(1024);
+  if Assigned(pc) then
+    try
+      SetString(Result, pc, wvsprintf(pc, PCHAR(fmt), PCHAR(pdw1)));
+    finally
+      if (pdw1 <> nil) then FreeMem(pdw1);
+      FreeMem(pc);
+    end
+  else
+    Result := '';
+end;
+
+
+// -----------------------------------------------------------------------------
+
+function UpperCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        Result[i] := UpCase(s[i]);
+    end;
+end;
+
+function LowerCase(const s: string): string;
+var
+  i : integer;
+begin
+  Result := '';
+
+  if(length(s) > 0) then
+    begin
+      SetLength(Result,length(s));
+      for i := 1 to length(s) do
+        case s[i] of
+          'A'..'Z','Ä','Ö','Ü':
+            Result[i] := CHR(BYTE(s[i]) + 32);
+          else
+            Result[i] := s[i];
+        end;
+    end;
+end;
+
+function LoggedUser: string;
+var
+  dwLen  : dword;
+  fTest  : boolean;
+begin
+  Result := '';
+  dwLen  := MAX_PATH; SetLength(Result,dwLen);
+
+  fTest  := GetUserName(@Result[1],dwLen);
+
+  if(not fTest) and (GetLastError = ERROR_MORE_DATA) then begin
+    SetLength(Result,dwLen);
+    fTest := GetUserName(@Result[1],dwLen);
+  end;
+
+  if(fTest) and (Result[1] <> #0) then
+    SetLength(Result,dwLen - 1);
+end;
+
+// -----------------------------------------------------------------------------
+
+//
+// delete files during next reboot (code by sakura)
+//
+function DeleteFileDuringNextSystemBoot(aFileName: string): Boolean;
+var
+  ShortName,
+  winini    : string;
+  os        : TOSVersionInfo;
+  ts        : array of string;
+  f         : TextFile;
+  i         : integer;
+begin
+  Result := False;
+
+  // get OS version
+  os.dwOSVersionInfoSize := sizeof(TOSVersionInfo);
+  GetVersionEx(os);
+
+  case os.dwPlatformId of
+    // NT systems
+    VER_PLATFORM_WIN32_NT:
+      Result := MoveFileEx(pchar(aFileName),nil,
+        MOVEFILE_REPLACE_EXISTING + MOVEFILE_DELAY_UNTIL_REBOOT);
+    // 9x systems
+    VER_PLATFORM_WIN32_WINDOWS:
+      begin
+        // get Windows folder
+        SetLength(winini,MAX_PATH+1);
+        SetLength(winini,GetWindowsDirectory(@winini[1],MAX_PATH+1));
+
+        if(winini <> '') then begin
+          if(winini[length(winini)] <> '\') then
+            winini := winini + '\';
+          winini   := winini + 'wininit.ini';
+
+          // get short name of the given file
+          SetLength(ShortName,MAX_PATH+1);
+          SetLength(ShortName,
+            GetShortPathName(@aFilename[1],@ShortName[1],MAX_PATH+1));
+
+          if(ShortName <> '') then begin
+            // add it to "wininit.ini" to delete
+            // during next reboot
+            SetLength(ts,0);
+
+            {$I-}
+            // get old file´s content
+            AssignFile(f,winini);
+            ReSet(f);
+            if(IoResult = 0) then begin
+              while(not eof(f)) do begin
+                SetLength(ts,length(ts)+1);
+                ReadLn(f,ts[length(ts)-1]);
+
+                if(lstrcmpi('[rename]',pchar(ts[length(ts)-1])) = 0) then begin
+                  SetLength(ts,length(ts)+1);
+                  ts[length(ts)-1] := 'NUL='+ShortName;
+                end;
+              end;
+              CloseFile(f);
+            end;
+
+            if(length(ts) = 0) then begin
+              SetLength(ts,2);
+              ts[0] := '[rename]';
+              ts[1] := 'NUL='+ShortName;
+            end;
+
+            // re-create
+            ReWrite(f);
+            Result := (IoResult = 0);
+            if(Result) then begin
+              for i := 0 to length(ts) - 1 do
+                WriteLn(f,ts[i]);
+
+              CloseFile(f);
+            end;
+            {$I+}
+
+            SetLength(ts,0);
+          end;
+        end;
+      end;
+    // only 9x and NT are supported
+    else
+      exit;
+  end;
+end;
Index: /oup/releases/0.32a/src/TFileTypeRegistration/demo.txt
===================================================================
--- /oup/releases/0.32a/src/TFileTypeRegistration/demo.txt	(revision 8)
+++ /oup/releases/0.32a/src/TFileTypeRegistration/demo.txt	(revision 8)
@@ -0,0 +1,34 @@
+uses
+  ftypesAPI;
+
+var
+  ftr    : TFileTypeRegistration;
+  s:String;
+
+
+ftr := TFileTypeRegistration.Create;
+if(ftr <> nil) then begin
+  try
+    if(LOWORD(wp) = IDC_CREATEFOO) then begin
+      if(ftr.RegisterType('.foo','FooFile','FOO-File')) then begin
+        ftr.AddHandler('open','notepad.exe "%1"','Öffnen');
+        ftr.AddHandler('print','notepad.exe /p "%1"');
+        ftr.SetDefaultHandler;
+        ftr.AddNewFileSupport('.foo');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_DELPRINTVERB) then begin
+      if(ftr.GetInternalKey('.foo') <> '') then begin
+        ftr.DeleteHandler('print');
+        ftr.SetDefaultHandler('open');
+      end;
+    end;
+    if(LOWORD(wp) = IDC_REMOVEFOO) then begin
+      s := ftr.GetInternalKey('.foo');
+      if(MessageBox(hwndDlg,pchar('Wollen Sie wirklich ".foo" und "' + s + '" entfernen?'), 'Frage',MB_YESNO or MB_DEFBUTTON2 or MB_ICONQUESTION) = ID_YES) then
+        ftr.UnregisterType('.foo');
+    end;
+  finally
+    ftr.Free;
+  end;
+end;
Index: /oup/releases/0.32a/src/TFileTypeRegistration/ftypesAPI.pas
===================================================================
--- /oup/releases/0.32a/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
+++ /oup/releases/0.32a/src/TFileTypeRegistration/ftypesAPI.pas	(revision 8)
@@ -0,0 +1,544 @@
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse (Win32-API)
+// Copyright (c) 2004 Mathias Simmack
+//
+// -----------------------------------------------------------------------------
+
+// -- Revision history ---------------------------------------------------------
+//
+//   * erste Version
+//
+// -----------------------------------------------------------------------------
+unit ftypesAPI;
+
+interface
+
+uses
+  Windows, ShlObj;
+
+type
+  TFileTypeRegistration = class
+    FRegConnector : HKEY;
+    FExtension,
+    FInternalName : string;
+    FVerb         : string;
+  public
+    constructor Create;
+    destructor Destroy; override;
+    function RegisterType(const Extension, InternalName: string;
+      Description: string = ''; IconFile: string = '';
+      IconIndex: integer = -1): boolean;
+    function UnregisterExtension(const Extension: string): boolean;
+    function UnregisterType(const Extension: string): boolean;
+    procedure UpdateShell;
+    function AddHandler(const HandlerVerb, CommandLine: string;
+      HandlerDescription: string = ''): boolean; overload;
+    function DeleteHandler(const HandlerVerb: string): boolean;
+    function SetDefaultHandler: boolean; overload;
+    function SetDefaultHandler(const HandlerVerb: string): boolean; overload;
+    function GetInternalKey(const Extension: string): string;
+    function AddNewFileSupport(const Extension: string): boolean;
+    function RemoveNewFileSupport(const Extension: string): boolean;
+
+    property Extension: string read FExtension;
+    property InternalName: string read FInternalName;
+    property CurrentVerb: string read FVerb;
+  end;
+
+
+implementation
+
+(* *****************************************************************************
+
+  Beispiel #1: Einen neuen Dateityp registrieren
+  ----------------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // die Dateiendung ".foo" registrieren, der interne Schlüssel
+    // lautet "FooFile", eine Beschreibung und eine Symboldatei
+    // sind ebenfalls angegeben
+    if(ftr.RegisterType('.foo','FooFile','FOO Description',
+      'c:\folder\icon.ico')) then
+    begin
+      // fügt den Handler "open" hinzu und verknüpft ihn mit dem
+      // Programm "foo.exe"
+      ftr.AddHandler('open','"c:\folder\foo.exe" "%1"');
+
+      // setzt den zuletzt benutzten Handler ("open" in dem Fall)
+      // als Standard
+      ftr.SetDefaultHandler;
+    end;
+
+    if(ftr.RegisterType('.foo','ThisIsNotTheFOOKey')) then
+    // Das ist kein Fehler! Obwohl hier der interne Name
+    // "ThisIsNotTheFOOKey" verwendet wird, benutzt die Funktion
+    // intern den bereits vorhandenen Schlüssel "FooFile" (s. oben).
+    begin
+      // zwei neue Handler werden registriert, ...
+      ftr.AddHandler('print','"c:\folder\foo.exe" /p "%1"');
+      ftr.AddHandler('edit','notepad.exe "%1"');
+
+      // ... & dank der überladenen Funktion "SetDefaultHandler"
+      // kann diesmal auch "print" als Standardhandler gesetzt
+      // werden
+      ftr.SetDefaultHandler('print');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #2: Einen neuen Typ mit einem vorhandenen Schlüssel
+  verknüpfen
+  ------------------------------------------------------------
+
+  Das Beispiel registriert die Endung ".foo" auf die gleiche
+  Weise wie Textdateien (.txt). Es wird einfach der interne
+  Schlüsselname ermittelt und für die Endung ".foo" gesetzt
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    strInternalTextFileKey := ftr.GetInternalKey('.txt');
+    if(strInternalTextFileKey <> '') then
+      ftr.RegisterType('.foo',strInternalTextFileKey);
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #3: Einen Handler entfernen
+  ------------------------------------
+
+  ftr := TFileTypeRegistration.Create;
+  if(ftr <> nil) then
+  try
+    // den internen Schlüsselnamen des Typs ".foo" ermitteln, ...
+    if(ftr.GetInternalKey('.foo') <> '') then
+    // ... wobei das Ergebnis in dem Fall unwichtig ist, weil
+    // intern auch die Eigenschaft "FInternalName" gesetzt
+    // wird
+    begin
+      // den "print"-Handler entfernen, ...
+      ftr.DeleteHandler('print');
+
+      // ... & den Standardhandler aktualisieren
+      ftr.SetDefaultHandler('open');
+    end;
+  finally
+    ftr.Free;
+  end;
+
+
+  Beispiel #4: Nur eine Dateiendung entfernen
+  -------------------------------------------
+
+  In diesem Fall wird lediglich die Endung ".foo" entfernt. Der
+  evtl. vorhandene interne Schlüssel bleibt bestehen. Das ist
+  für das Beispiel #2 nützlich, wenn die Endung ".foo" entfernt
+  werden soll, intern aber mit den Textdateien verlinkt ist, die
+  ja im Normalfall nicht entfernt werden dürfen/sollten.
+
+    ftr.UnregisterExtension('.foo');
+
+
+  Beispiel #5: Den kompletten Dateityp entfernen
+  ----------------------------------------------
+
+  Dieses Beispiel entfernt dagegen den kompletten Dateityp,
+  inkl. des evtl. vorhandenen internen Schlüssels (vgl. mit
+  Beispiel #4).
+
+    ftr.UnregisterType('.foo');
+
+  Bezogen auf Beispiel #2 wäre das die fatale Lösung, weil dadurch
+  zwar die Endung ".foo" deregistriert wird, gleichzeitig wird
+  aber auch der intern verwendete Schlüssel der Textdateien
+  gelöscht.
+
+  ALSO, VORSICHT!!!
+
+***************************************************************************** *)
+
+
+//
+// Admin-Rechte sind erforderlich (Funktion von NicoDE)
+//
+{$INCLUDE IsAdmin.inc}
+{$INCLUDE SysUtils.inc}
+
+
+// -----------------------------------------------------------------------------
+//
+// Registry
+//
+// -----------------------------------------------------------------------------
+
+function RegWriteSubKeyVal(const parent: HKEY; SubKeyName: string;
+  ValueName, Value: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := false;
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegCreateKeyEx(parent,pchar(SubKeyName),0,nil,0,KEY_READ or KEY_WRITE,
+    nil,tmp,nil) = ERROR_SUCCESS) then
+  try
+    Result := (RegSetValueEx(tmp,pchar(ValueName),0,REG_SZ,pchar(Value),
+      length(Value) + 1) = ERROR_SUCCESS);
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegReadSubKeyStr(const parent: HKEY; SubKeyName: string;
+  ValueName: string): string;
+var
+  tmp     : HKEY;
+  lpData,
+  dwLen   : dword;
+begin
+  Result  := '';
+  if(parent = INVALID_HANDLE_VALUE) or
+    (SubKeyName = '') then exit;
+
+  if(RegOpenKeyEx(parent,pchar(SubKeyName),0,KEY_READ,
+    tmp) = ERROR_SUCCESS) then
+  try
+    lpData := REG_NONE;
+    dwLen  := 0;
+    if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,nil,
+         @dwLen) = ERROR_SUCCESS) and
+      (lpData in[REG_SZ,REG_EXPAND_SZ]) and
+      (dwLen > 0) then
+    begin
+      SetLength(Result,dwLen);
+
+      if(RegQueryValueEx(tmp,pchar(ValueName),nil,@lpData,
+           @Result[1],@dwLen) = ERROR_SUCCESS) then
+        SetLength(Result,dwLen - 1)
+      else
+        Result := '';
+    end;
+  finally
+    RegCloseKey(tmp);
+  end;
+end;
+
+function RegKeyExists(const parent: HKEY; KeyName: string): boolean;
+var
+  tmp    : HKEY;
+begin
+  Result := (RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,tmp) =
+    ERROR_SUCCESS);
+  if(Result) then RegCloseKey(tmp);
+end;
+
+function RegDeleteWholeKey(parent: HKEY; KeyName: string): boolean;
+var
+  reg       : HKEY;
+  dwSubkeys : dword;
+  dwLen     : dword;
+  i         : integer;
+  buf       : array[0..MAX_PATH]of char;
+begin
+  if(RegOpenKeyEx(parent,pchar(KeyName),0,KEY_READ,reg) = ERROR_SUCCESS) then
+  try
+    if(RegQueryInfoKey(reg,nil,nil,nil,@dwSubKeys,nil,
+      nil,nil,nil,nil,nil,nil) = ERROR_SUCCESS) and
+      (dwSubKeys > 0) then
+    for i := 0 to dwSubKeys - 1 do begin
+      ZeroMemory(@buf,sizeof(buf));
+      dwLen   := MAX_PATH;
+
+      if(RegEnumKeyEx(reg,i,buf,dwLen,nil,nil,nil,nil) = ERROR_SUCCESS) and
+        (dwLen > 0) then
+      RegDeleteWholeKey(reg,buf);
+    end;
+  finally
+    RegCloseKey(reg);
+  end;
+
+  Result := (RegDeleteKey(parent,pchar(KeyName)) = ERROR_SUCCESS);
+end;
+
+
+// -----------------------------------------------------------------------------
+//
+// TFileTypeRegistration-Klasse
+//
+// -----------------------------------------------------------------------------
+
+constructor TFileTypeRegistration.Create;
+var
+  key: HKEY;
+  sub: PChar;
+begin
+  FExtension    := '';
+  FInternalName := '';
+  FVerb         := '';
+
+  // Zugriff auf die Registry, & HKEY_CLASSES_ROOT
+  // als Root setzen
+  if(WVersion='9X') or IsAdmin then begin
+    key:=HKEY_CLASSES_ROOT;
+    sub:=nil;
+  end else begin
+    key:=HKEY_CURRENT_USER;
+    sub:=PChar('SOFTWARE\Classes');
+  end;
+
+  if RegOpenKeyEx(key,sub,0,KEY_ALL_ACCESS, FRegConnector) <> ERROR_SUCCESS then
+    FRegConnector := INVALID_HANDLE_VALUE;
+end;
+
+destructor TFileTypeRegistration.Destroy;
+begin
+  if(FRegConnector <> INVALID_HANDLE_VALUE) then
+    RegCloseKey(FRegConnector);
+end;
+
+function TFileTypeRegistration.RegisterType(const Extension,
+  InternalName: string; Description: string = ''; IconFile: string = '';
+  IconIndex: integer = -1): boolean;
+var
+  strDummy : string;
+begin
+  // Standardergebnis
+  Result         := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // ist dieser Typ evtl. schon registriert?
+  strDummy := self.GetInternalKey(Extension);
+
+  // Nein. :o)
+  if(strDummy = '') then strDummy := InternalName;
+
+  // den Schlüssel mit der Dateiendung anlegen oder aktualisieren
+  Result := RegWriteSubKeyVal(FRegConnector,Extension,'',strDummy);
+  if(not Result) then exit;
+
+  // den internen Schlüssel öffnen
+  if(Result) then
+  begin
+    // Beschreibung anlegen
+    if(Description <> '') then
+      RegWriteSubKeyVal(FRegConnector,strDummy,'',Description);
+
+    // Symbol zuweisen (Datei muss existieren!)
+    if(IconFile <> '') and
+      (fileexists(IconFile)) then
+    begin
+      if(IconIndex <> -1) then
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',Format('%s,%d',[IconFile,IconIndex]))
+      else
+        RegWriteSubKeyVal(FRegConnector,strDummy + '\DefaultIcon',
+          '',IconFile);
+    end;
+  end;
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+
+  // Properties aktualisieren
+  if(Result) then
+  begin
+    FExtension    := Extension;
+    FInternalName := strDummy;
+  end;
+end;
+
+function TFileTypeRegistration.UnregisterExtension(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // die Endung entfernen
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegDeleteWholeKey(FRegConnector,Extension));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+function TFileTypeRegistration.UnregisterType(const Extension: string):
+  boolean;
+var
+  strDummy : string;
+begin
+  Result   := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // den internen Namen der Endung ermitteln
+  strDummy := self.GetInternalKey(Extension);
+
+  // die Endung entfernen (s. "UnregisterExtension"), ...
+  Result   := (self.UnregisterExtension(Extension)) and
+  // ... & den internen Schlüssel löschen
+    (strDummy <> '') and
+    (RegKeyExists(FRegConnector,strDummy)) and
+    (RegDeleteWholeKey(FRegConnector,strDummy));
+
+  // Systemsymbole aktualisieren
+  self.UpdateShell;
+end;
+
+procedure TFileTypeRegistration.UpdateShell;
+begin
+  SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,nil,nil);
+end;
+
+
+const
+  ShellKey = '%s\shell\%s';
+
+function TFileTypeRegistration.AddHandler(const HandlerVerb,
+  CommandLine: string; HandlerDescription: string = ''): boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') or
+    (CommandLine = '') then exit;
+
+  // der interne Schlüssel muss existieren
+  if(RegKeyExists(FRegConnector,FInternalName)) then
+  begin
+    // den Handler (= Verb) erzeugen
+    Result := RegWriteSubKeyVal(FRegConnector,
+      Format(ShellKey + '\command',[FInternalName,HandlerVerb]),
+      '',
+      CommandLine);
+
+    // ggf. Beschreibung für Handler setzen
+    if(HandlerDescription <> '') then
+      RegWriteSubKeyVal(FRegConnector,
+        Format(ShellKey,[FInternalName,HandlerVerb]),
+        '',
+        HandlerDescription);
+  end;
+
+  // interne Eigenschaft anpassen (für "SetDefaultHandler")
+  if(Result) then
+    FVerb := HandlerVerb;
+end;
+
+function TFileTypeRegistration.DeleteHandler(const HandlerVerb: string):
+  boolean;
+begin
+  // Standardergebnis
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // Handlerschlüssel entfernen (sofern vorhanden)
+  Result :=
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) and
+    (RegDeleteWholeKey(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb])));
+end;
+
+function TFileTypeRegistration.SetDefaultHandler: boolean;
+begin
+  if(FInternalName <> '') and (FVerb <> '') then
+    Result := self.SetDefaultHandler(FVerb)
+  else
+    Result := false;
+end;
+
+function TFileTypeRegistration.SetDefaultHandler(const HandlerVerb: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (FInternalName = '') or
+    (HandlerVerb = '') then exit;
+
+  // interner Schlüssel muss existieren, ...
+  if(RegKeyExists(FRegConnector,FInternalName)) and
+  // ... & Handler muss existieren, ...
+    (RegKeyExists(FRegConnector,
+       Format(ShellKey,[FInternalName,HandlerVerb]))) then
+  begin
+  // ... dann den Handler als Standard eintragen
+    Result := RegWriteSubKeyVal(FRegConnector,FInternalName + '\shell',
+      '',HandlerVerb);
+  end;
+end;
+
+function TFileTypeRegistration.GetInternalKey(const Extension: string): string;
+begin
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // einen evtl. eingestellten internen Namen zurücksetzen
+  FInternalName   := '';
+
+  // den Schlüssel der Dateiendung öffnen, ...
+  if(RegKeyExists(FRegConnector,Extension)) then
+    FInternalName := RegReadSubKeyStr(FRegConnector,Extension,'');
+
+  // ... als Funktionsergebnis zurückliefern
+  if(not RegKeyExists(FRegConnector,FInternalName)) then
+    FInternalName := '';
+
+  Result := FInternalName;
+end;
+
+
+function TFileTypeRegistration.AddNewFileSupport(const Extension: string):
+  boolean;
+var
+  Description : string;
+begin
+  Result      := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  // interne Beschreibung des Typs ermitteln
+  if(self.GetInternalKey(Extension) <> '') then
+    Description := RegReadSubKeyStr(FRegConnector,FInternalName,'')
+  else
+    Description := '';
+
+  // die Beschreibung darf keine Leerzeichen enthalten, weil sie
+  // als Referenz für den neuen Dateinamen verwendet wird, ...
+  if(pos(#32,Description) > 0) or
+  // ... & sie darf auch nicht leer sein
+    (Description = '') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension)) and
+    (RegWriteSubKeyVal(FRegConnector,Extension + '\ShellNew','NullFile',''));
+end;
+
+function TFileTypeRegistration.RemoveNewFileSupport(const Extension: string):
+  boolean;
+begin
+  Result := false;
+  if(FRegConnector = INVALID_HANDLE_VALUE) or
+    (Extension = '') or
+    (Extension[1] <> '.') then exit;
+
+  Result := (RegKeyExists(FRegConnector,Extension + '\ShellNew')) and
+    (RegDeleteWholeKey(FRegConnector,Extension + '\ShellNew'));
+end;
+
+end.
Index: /oup/releases/0.32a/src/Unit10_leveldb.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit10_leveldb.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit10_leveldb.dfm	(revision 8)
@@ -0,0 +1,61 @@
+object Form10: TForm10
+  Left = 0
+  Top = 0
+  BorderStyle = bsNone
+  Caption = 'Creating DB'
+  ClientHeight = 89
+  ClientWidth = 400
+  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.32a/src/Unit10_leveldb.pas
===================================================================
--- /oup/releases/0.32a/src/Unit10_leveldb.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit10_leveldb.pas	(revision 8)
@@ -0,0 +1,1176 @@
+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(source,target:String);
+    PROCEDURE CreateLevel(source,target:String);
+  END;
+
+
+VAR
+  Form10: TForm10;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES ABSMain, ABSDecUtil, Unit1_main, Unit2_functions, Unit3_data, Unit6_imgfuncs, Unit9_data_structures, Unit15_Classes;
+
+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;
+  DataBase:TABSDatabase;
+  Query:TABSQuery;
+  MimeCoder: TStringFormat_MIME64;
+VAR
+  DatHeader:THeader;
+  FilesHeader:TFilesMap;
+  NamedFilesHeader:TNamedFilesMap;
+  ExtensionsHeader:TExtensionsMap;
+  Stream_Body,Stream_Names:TMemoryStream;
+  Stream_Dat,Stream_Raw,Stream_Sep:TFileStream;
+
+PROCEDURE TForm10.CreateLevel(source,target:String);
+  VAR
+    files:LongWord;
+    
+    i,j:LongWord;
+    temps,temps2:String;
+    data,rawdata:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+    extlist:TExtensionsMap;
+    fileinfo:TFileInfo;
+    datlinks:TDatLinks;
+    OniImage:TOniImage;
+    levelid:LongWord;
+  CONST
+    steps:Byte=3;
+  PROCEDURE DoStep(stepname:String);
+    BEGIN
+      Inc(step);
+      IF stepname<>'FIN' THEN
+        group_progress.Caption:='Creating Dat (Step '+IntToStr(step)+'/'+IntToStr(steps)+': '+stepname+')'
+      ELSE
+        group_progress.Caption:='Creating Dat (FINISHED)';
+    END;
+  BEGIN
+
+//
+// FILE EXISTS CHECK FÜR DAT/RAW/SEP!!!
+//
+
+    IF NOT CreateDataConnection(source,ODB_ADB) THEN BEGIN
+      ShowMessage('Could not connect to .oldb-file');
+      Exit;
+    END;
+    levelid:=OniDataConnection.LevelInfo.LevelNumber;
+    levelid:=(levelid*2) SHR (3*8) + $01;
+    OniImage:=TOniImage.Create;
+
+    absolutebegintime:=Time;
+
+    Form10.Visible:=True;
+    Form1.Visible:=False;
+    step:=0;
+    converting:=True;
+    abort:=False;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+    absolutebegintime:=Time;
+
+    Stream_Body:=TMemoryStream.Create;
+    Stream_Names:=TMemoryStream.Create;
+    Stream_Dat:=TFileStream.Create(target,fmCreate);
+    Stream_Raw:=TFileStream.Create(AnsiReplaceStr(target,'.dat','.raw'),fmCreate);
+    IF OniDataConnection.OSisMac THEN
+      Stream_Sep:=TFileStream.Create(AnsiReplaceStr(target,'.dat','.sep'),fmCreate);
+
+    DoStep('Creating header');
+    progress.Position:=0;
+    lbl_progress.Caption:='';
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+    Application.ProcessMessages;
+
+    NamedFilesHeader:=TOniDataADB(OniDataConnection).GetNamedFilesMap;
+    extlist:=OniDataConnection.GetExtendedExtensionsList;
+    FOR i:=0 TO High(DatHeader.Ident) DO
+      DatHeader.Ident[i]:=OniDataConnection.LevelInfo.Ident[i];
+    DatHeader.Files:=OniDataConnection.GetFilesCount;
+    DatHeader.NamedFiles:=Length(NamedFilesHeader);
+    DatHeader.Extensions:=Length(extlist);
+    DatHeader.DataAddr:=0;
+    DatHeader.DataSize:=0;
+    DatHeader.NamesAddr:=0;
+    DatHeader.NamesSize:=0;
+    FOR i:=0 TO High(DatHeader.Ident2) DO
+      DatHeader.Ident2[i]:=0;
+    SetLength(FilesHeader, DatHeader.Files);
+    SetLength(ExtensionsHeader, DatHeader.Extensions);
+
+    DoStep('Writing extensions-header');
+    progress.Max:=Length(OniDataConnection.GetExtensionsList);
+    Application.ProcessMessages;
+
+    FOR i:=0 TO High(ExtensionsHeader) DO BEGIN
+      ExtensionsHeader[i].Ident:=extlist[i].Ident;
+      ExtensionsHeader[i].Extension:=extlist[i].Extension;
+      SetLength(temps,4);
+      FOR j:=0 TO 3 DO
+        temps[j+1]:=ExtensionsHeader[i].Extension[3-j];
+      ExtensionsHeader[i].ExtCount:=Length(OniDataConnection.GetFilesList(temps,'',False));
+      progress.Position:=i+1;
+      lbl_progress.Caption:='Extensions done: '+IntToStr(i+1)+'/'+IntToStr(Length(extlist));
+      Application.ProcessMessages;
+    END;
+
+    DoStep('Storing files-data');
+    progress.Position:=0;
+    progress.Max:=DatHeader.Files;
+    lbl_progress.Caption:='';
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+    Application.ProcessMessages;
+
+    begintime:=Time;
+    FOR i:=0 TO DatHeader.Files-1 DO BEGIN
+      fileinfo:=OniDataConnection.GetFileInfo(i);
+      FOR j:=0 TO 3 DO
+        FilesHeader[i].Extension[j]:=fileinfo.Extension[4-j];
+      IF fileinfo.Size>0 THEN BEGIN
+//        DatLinks:=;
+        FilesHeader[i].DataAddr:=Stream_Body.Size+8;
+        data:=OniDataConnection.LoadDatFile(i);
+
+
+        IF (Pos(UpperCase(fileinfo.Extension),UpperCase(raws)) MOD 4)=1 THEN BEGIN
+          rawlist:=OniDataConnection.GetRawList(i);
+          IF Length(rawlist)>0 THEN BEGIN
+            FOR j:=0 TO High(rawlist) DO BEGIN
+              IF rawlist[j].raw_size>0 THEN BEGIN
+                IF (UpperCase(fileinfo.Extension)='TXMP') AND ((data[$88] AND $01)>0) THEN BEGIN
+                  OniImage.LoadFromTXMP(i);
+                  OniImage.GetMipMappedImage(rawdata);
+                  rawlist[j].raw_size:=OniImage.GetImageDataSize(true);
+                  data[$90]:=08;
+                END ELSE BEGIN
+                  SetLength(rawdata,rawlist[j].raw_size);
+                  OniDataConnection.LoadRawFile(i,rawlist[j].src_offset,@rawdata[0]);
+                END;
+
+                IF rawlist[j].loc_sep THEN BEGIN
+                  rawlist[j].raw_addr:=Stream_Sep.Size;
+                  Stream_Sep.Write(rawdata[0],Length(rawdata));
+                END ELSE BEGIN
+                  rawlist[j].raw_addr:=Stream_Raw.Size;
+                  Stream_Raw.Write(rawdata[0],Length(rawdata));
+                END;
+              END ELSE rawlist[j].raw_addr:=0;
+              data[rawlist[j].src_offset+0]:=(rawlist[j].raw_addr       ) AND $FF;
+              data[rawlist[j].src_offset+1]:=(rawlist[j].raw_addr SHR  8) AND $FF;
+              data[rawlist[j].src_offset+2]:=(rawlist[j].raw_addr SHR 16) AND $FF;
+              data[rawlist[j].src_offset+3]:=(rawlist[j].raw_addr SHR 24) AND $FF;
+            END;
+          END;
+        END;
+
+        Stream_Body.Write(data[0],Length(data));
+//
+      END ELSE
+        FilesHeader[i].DataAddr:=0;
+      IF Length(fileinfo.Name)>0 THEN BEGIN
+        FilesHeader[i].NameAddr:=Stream_Names.Size;
+        temps:=fileinfo.Extension+fileinfo.Name+Chr(0);
+        Stream_Names.Write(temps[1],Length(temps)); 
+      END ELSE
+        FilesHeader[i].NameAddr:=0;
+      FilesHeader[i].FileSize:=fileinfo.Size;
+      FilesHeader[i].FileType:=fileinfo.FileType;
+
+      IF ( (i MOD 25)=0 ) AND (i>=100) THEN
+        lbl_estimation.Caption:='Estimated finishing time: '+TimeToStr((Time-begintime)/i*progress.Max+begintime);
+      progress.Position:=i+1;
+      lbl_progress.Caption:='Files done: '+IntToStr(i+1)+'/'+IntToStr(progress.Max);
+      Application.ProcessMessages;
+    END;
+
+    Stream_Dat.Write(DatHeader,SizeOf(DatHeader));
+    FOR i:=0 TO High(FilesHeader) DO
+      Stream_Dat.Write(FilesHeader[i],SizeOf(FilesHeader[i]));
+    FOR i:=0 TO High(NamedFilesHeader) DO
+      Stream_Dat.Write(NamedFilesHeader[i],SizeOf(NamedFilesHeader[i]));
+    FOR i:=0 TO High(ExtensionsHeader) DO
+      Stream_Dat.Write(ExtensionsHeader[i],SizeOf(ExtensionsHeader[i]));
+
+    DatHeader.DataSize:=Stream_Body.Size;
+    DatHeader.NamesSize:=Stream_Names.Size;
+    DatHeader.DataAddr:=Stream_Dat.Size;
+    Stream_Body.Seek(0,soFromBeginning);
+    Stream_Dat.CopyFrom(Stream_Body,Stream_Body.Size);
+    DatHeader.NamesAddr:=Stream_Dat.Size;
+    Stream_Names.Seek(0,soFromBeginning);
+    Stream_Dat.CopyFrom(Stream_Names,Stream_Names.Size);
+
+    Stream_Dat.Seek(0,soFromBeginning);
+    Stream_Dat.Write(DatHeader,SizeOf(DatHeader)); 
+
+    Stream_Dat.Free;
+    Stream_Body.Free;
+    Stream_Names.Free;
+    Stream_Raw.Free;
+    IF OniDataConnection.OSisMac THEN
+      Stream_Sep.Free;
+
+    progress.Position:=progress.Max;
+    lbl_progress.Caption:='Files done: '+IntToStr(progress.Max)+'/'+IntToStr(progress.Max);
+    lbl_estimation.Caption:='FINISHED (duration: '+TimeToStr(Time-absolutebegintime)+')';
+
+    DoStep('FIN');
+    btn_abortok.Caption:='&OK';
+    btn_abortok.Default:=True;
+
+    OniImage.Free;
+
+    converting:=False;
+
+    CloseDataConnection;
+  END;
+
+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(source,target:String);
+  VAR
+    i,j:LongWord;
+    temps,temps2:String;
+    data:Tdata;
+    absolutebegintime,begintime:Double;
+    step:Byte;
+    rawlist:TRawList;
+    extlist:TExtensionsMap;
+    fileinfo:TFileInfo;
+  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
+    IF NOT CreateDataConnection(source,ODB_Dat) THEN BEGIN
+      ShowMessage('Could not connect to .dat-file');
+      Exit;
+    END ELSE BEGIN
+      TOniDataDat(OniDataConnection).UnloadWhenUnused:=False;
+    END;
+
+    Form10.Visible:=True;
+    Form1.Visible:=False;
+    step:=0;
+    converting:=True;
+    abort:=False;
+    btn_abortok.Caption:='&Abort...';
+    btn_abortok.Default:=False;
+    loaded_filename:=target;
+
+    absolutebegintime:=Time;
+
+    DataBase:=TABSDatabase.Create(Self);
+    DataBase.DatabaseName:='OLDB';
+    DataBase.DatabaseFileName:=target;
+    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, sep BOOLEAN, 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(OniDataConnection.LevelInfo.Ident));
+    FOR i:=0 TO High(OniDataConnection.LevelInfo.Ident) DO data[i]:=OniDataConnection.LevelInfo.Ident[i];
+    temps:=CreateHexString(data,True);
+    Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("ident","'+temps+'");';
+    Query.ExecSQL;
+    Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("lvl","'+IntToStr(OniDataConnection.LevelInfo.LevelNumber)+'");';
+    Query.ExecSQL;
+    IF OniDataConnection.OSisMAC THEN
+      Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("os","MAC");'
+    ELSE
+      Query.SQL.Text:='INSERT INTO globals (name,value) VALUES ("os","PC");';
+    Query.ExecSQL;
+
+    DoStep('Writing extensionslist');
+    progress.Max:=Length(OniDataConnection.GetExtensionsList);
+    Application.ProcessMessages;
+
+    extlist:=OniDataConnection.GetExtendedExtensionsList;
+    FOR i:=0 TO High(extlist) DO BEGIN
+      SetLength(data,Length(extlist[i].Ident));
+      FOR j:=0 TO High(extlist[i].Ident) DO data[j]:=extlist[i].Ident[j];
+      temps:=CreateHexString(data,True);
+      temps2:=extlist[i].Extension[3]+extlist[i].Extension[2]+extlist[i].Extension[1]+extlist[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(Length(extlist));
+      Application.ProcessMessages;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    lbl_progress.Caption:='';
+
+    progress.Position:=0;
+    lbl_progress.Caption:='Files done: '+IntToStr(0)+'/'+IntToStr(OniDataConnection.GetFilesCount);
+    lbl_estimation.Caption:='Estimated finishing time: unknown';
+
+    DoStep('Loading .dat into memory');
+    Application.ProcessMessages;
+
+    progress.Max:=OniDataConnection.GetFilesCount;
+    begintime:=Time;
+    DoStep('Writing .dat-fileslist');
+    Application.ProcessMessages;
+
+    Database.StartTransaction;
+    FOR i:=0 TO OniDataConnection.GetFilesCount-1 DO BEGIN
+      fileinfo:=OniDataConnection.GetFileInfo(i);
+      IF (fileinfo.FileType AND $02)=0 THEN BEGIN
+        mimecoder:=TStringFormat_MIME64.Create;
+        data:=OniDataConnection.LoadDatFile(i);
+        Query.SQL.Text:='INSERT INTO datfiles (id,extension,name,contenttype,size,data) VALUES ('+IntToStr(i)+',"'+fileinfo.Extension+'","'+fileinfo.Name+'","'+IntToHex(fileinfo.FileType,8)+'",'+IntToStr(fileinfo.Size)+',MimeToBin("'+MimeCoder.StrTo(@data[0], Length(data))+'") );';
+        Query.ExecSQL;
+        mimecoder.Free;
+
+        rawlist:=OniDataConnection.GetRawList(i);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR j:=0 TO High(rawlist) DO BEGIN
+            IF rawlist[j].raw_size>0 THEN BEGIN
+              SetLength(data, rawlist[j].raw_size);
+              OniDataConnection.LoadRawFile(i,rawlist[j].src_offset,data);
+              mimecoder:=TStringFormat_MIME64.Create;
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,sep,size,data) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+BoolToStr(rawlist[j].loc_sep)+','+IntToStr(rawlist[j].raw_size)+',MimeToBin("'+MimeCoder.StrTo(@data[0], rawlist[j].raw_size)+'") );';
+              Query.ExecSQL;
+              mimecoder.Free;
+            END ELSE BEGIN
+              Query.SQL.Text:='INSERT INTO rawmap (src_id,src_link_offset,sep,size) VALUES ('+IntToStr(i)+','+IntToStr(rawlist[j].src_offset)+','+BoolToStr(rawlist[j].loc_sep)+',0);';
+              Query.ExecSQL;
+            END;
+          END;
+        END;
+
+        HandleFile(fileinfo.Extension,i,True);
+      END ELSE BEGIN
+        Query.SQL.Text:='INSERT INTO datfiles (id,extension,name,contenttype,size) VALUES ('+IntToStr(i)+',"'+fileinfo.Extension+'","'+fileinfo.Name+'","'+IntToHex(fileinfo.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*progress.Max+begintime);
+      progress.Position:=i;
+      lbl_progress.Caption:='Files done: '+IntToStr(i)+'/'+IntToStr(progress.Max);
+      Application.ProcessMessages;
+      IF abort THEN BEGIN
+        stop_convert;
+        Exit;
+      END;
+    END;
+    Database.Commit(False);
+    progress.Position:=progress.Max;
+    lbl_progress.Caption:='Files done: '+IntToStr(progress.Max)+'/'+IntToStr(progress.Max);
+    lbl_estimation.Caption:='FINISHED (duration: '+TimeToStr(Time-absolutebegintime)+')';
+
+    DoStep('FIN');
+    btn_abortok.Caption:='&OK';
+    btn_abortok.Default:=True;
+
+    converting:=False;
+
+    database.Close;
+    database.Free;
+
+    CloseDataConnection;
+  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 InsertDatLinkToDB(fileid:LongWord; offset:LongWord);
+  VAR
+    link:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(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 AISA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:Word;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN BEGIN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*$160+$28);
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*$160+$150);
+      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 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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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 OBDC(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:Word;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*$18+$4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE OBOA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:Word;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1E,2,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO BEGIN
+          InsertDatLinkToDB(fileid,$20+i*240+$0);
+          InsertDatLinkToDB(fileid,$20+i*240+$4);
+          InsertDatLinkToDB(fileid,$20+i*240+$8);
+        END;
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE OFGA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:LongWord;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(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
+      InsertDatLinkToDB(fileid,$28);
+      InsertDatLinkToDB(fileid,$434);
+      InsertDatLinkToDB(fileid,$438);
+      InsertDatLinkToDB(fileid,$43C);
+      InsertDatLinkToDB(fileid,$C3C);
+      InsertDatLinkToDB(fileid,$C40);
+      InsertDatLinkToDB(fileid,$C44);
+      InsertDatLinkToDB(fileid,$C48);
+      InsertDatLinkToDB(fileid,$C88);
+      InsertDatLinkToDB(fileid,$C8C);
+    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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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,$40);
+      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,$0C);
+    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
+      OniDataConnection.LoadDatFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*8+$4);
+    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 STNA(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    packages:Word;
+    i:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(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);
+      OniDataConnection.LoadDatFilePart(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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      InsertDatLinkToDB(fileid,$40);
+      InsertDatLinkToDB(fileid,$44);
+    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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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
+      OniDataConnection.LoadDatFilePart(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);
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      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);
+  VAR
+    i:LongWord;
+    packages:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$20+i*8+$4);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE WMDD(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$11C,4,@packages);
+      IF packages>0 THEN
+        FOR i:=0 TO packages-1 DO InsertDatLinkToDB(fileid,$120+i*$124+$114);
+    END ELSE BEGIN
+    END;
+  END;
+PROCEDURE WMMB(fileid:LongWord; dir_dat2db:Boolean);
+  VAR
+    i:LongWord;
+    packages:LongWord;
+  BEGIN
+    IF dir_dat2db THEN BEGIN
+      OniDataConnection.LoadDatFilePart(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',True,AISA);
+  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',False,NIL);
+  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',True,OBDC);
+  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',False,NIL);
+  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',False,NIL);
+  InsertHandler('STNA',True,STNA);
+  InsertHandler('SUBT',False,NIL);
+  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',True,WMDD);
+  InsertHandler('WMM_',False,NIL);
+  InsertHandler('WMMB',True,WMMB);
+  InsertHandler('WPGE',True,WPGE);   
+END.
Index: /oup/releases/0.32a/src/Unit11_extractor.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit11_extractor.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit11_extractor.dfm	(revision 8)
@@ -0,0 +1,258 @@
+object Form11: TForm11
+  Left = 0
+  Top = 0
+  Caption = 'Extractor'
+  ClientHeight = 398
+  ClientWidth = 487
+  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 = 0
+        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
+      MultiSelect = True
+      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.32a/src/Unit11_extractor.pas
===================================================================
--- /oup/releases/0.32a/src/Unit11_extractor.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit11_extractor.pas	(revision 8)
@@ -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, Unit15_Classes;
+
+
+PROCEDURE TForm11.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+            END ELSE BEGIN
+              ExportFile(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]),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(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]),ExtractFileName(saved.FileName),settings,ExtractFileDir(saved.FileName));
+          END ELSE BEGIN
+            ExportFile(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]),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.32a/src/Unit12_ValueEdit.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit12_ValueEdit.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit12_ValueEdit.dfm	(revision 8)
@@ -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.32a/src/Unit12_ValueEdit.pas
===================================================================
--- /oup/releases/0.32a/src/Unit12_ValueEdit.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit12_ValueEdit.pas	(revision 8)
@@ -0,0 +1,119 @@
+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, Unit13_rawedit,Unit9_data_structures, Unit1_main;
+{$R *.dfm}
+VAR
+  caller_win_dat:TForm8;
+  caller_win_raw:TForm13;
+  _datatype:Word;
+  _offset:LongWord;
+
+
+PROCEDURE TForm12.MakeVarInput(objectname:String; offset:LongWord; datatype:Word; current:String; caller:TObject);
+  BEGIN
+    caller_win_dat:=NIL;
+    caller_win_raw:=NIL;
+    IF Pos('rawedit',TComponent(caller).Name)>0 THEN
+      caller_win_raw:=TForm13(caller)
+    ELSE
+      caller_win_dat:=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;
+    edit_new.BorderStyle:=bsSingle;
+    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;
+      13..16: BEGIN
+              Exit;
+              edit_new.EditType:=etInteger;
+              edit_new.LimitCheck:=True;
+              edit_new.Max:=Int((Power(256,datatype-13)) / 2)-1;
+              edit_new.Min:=1-Int((Power(256,datatype-13)) / 2)-1;
+            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;
+      IF caller_win_dat=NIL THEN
+        caller_win_raw.SetNewValue(_datatype,_offset,edit_new.Text)
+      ELSE
+        caller_win_dat.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.32a/src/Unit13_rawedit.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit13_rawedit.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit13_rawedit.dfm	(revision 8)
@@ -0,0 +1,304 @@
+object Form13: TForm13
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .raw-Editor'
+  ClientHeight = 640
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 640
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 640
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    OnResize = panel_dataResize
+    object Splitter2: TSplitter
+      Left = 0
+      Top = 450
+      Width = 483
+      Height = 9
+      Cursor = crVSplit
+      Align = alTop
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitTop = 209
+    end
+    object hex: TMPHexEditor
+      Left = 0
+      Top = 0
+      Width = 483
+      Height = 450
+      Cursor = crIBeam
+      Align = alTop
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -16
+      Font.Name = 'Courier'
+      Font.Style = []
+      OnKeyUp = hexKeyUp
+      ParentFont = False
+      TabOrder = 0
+      BytesPerRow = 16
+      Translation = tkAsIs
+      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
+      ExplicitLeft = -3
+      ExplicitTop = 3
+    end
+    object value_viewer: TWrapGrid
+      Left = 0
+      Top = 459
+      Width = 483
+      Height = 181
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      ParentFont = False
+      PopupMenu = value_viewer_context
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 640
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Splitter4: TSplitter
+      Left = 0
+      Top = 442
+      Width = 150
+      Height = 9
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 150
+    end
+    object panel_imexport: TPanel
+      Left = 0
+      Top = 580
+      Width = 150
+      Height = 60
+      Align = alBottom
+      BevelOuter = bvNone
+      TabOrder = 0
+      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
+    object group_file: TGroupBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 442
+      Align = alClient
+      Caption = '1. Select file'
+      TabOrder = 1
+      object list: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 337
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = listClick
+      end
+      object panel_extension: TPanel
+        Left = 2
+        Top = 352
+        Width = 146
+        Height = 88
+        Align = alBottom
+        BevelOuter = bvNone
+        TabOrder = 1
+        OnResize = panel_extensionResize
+        object lbl_filter: TLabel
+          Left = 2
+          Top = 46
+          Width = 100
+          Height = 17
+          AutoSize = False
+          Caption = 'Filter by &extension:'
+          FocusControl = combo_extension
+        end
+        object combo_extension: TComboBox
+          Left = 2
+          Top = 60
+          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 = 2
+          OnClick = combo_extensionClick
+        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 GroupBox1: TGroupBox
+      Left = 0
+      Top = 451
+      Width = 150
+      Height = 129
+      Align = alBottom
+      Caption = '2. Select .dat-link-offset'
+      TabOrder = 2
+      object list_offset: TListBox
+        Left = 2
+        Top = 15
+        Width = 146
+        Height = 112
+        Align = alClient
+        ItemHeight = 13
+        TabOrder = 0
+        OnClick = list_offsetClick
+      end
+    end
+  end
+  object value_viewer_context: TPopupMenu
+    AutoHotkeys = maManual
+    OnPopup = value_viewer_contextPopup
+    Left = 368
+    Top = 264
+    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
+  object opend: TOpenDialog
+    Options = [ofPathMustExist, ofFileMustExist, ofEnableSizing]
+    Left = 120
+    Top = 584
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 120
+    Top = 608
+  end
+end
Index: /oup/releases/0.32a/src/Unit13_rawedit.pas
===================================================================
--- /oup/releases/0.32a/src/Unit13_rawedit.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit13_rawedit.pas	(revision 8)
@@ -0,0 +1,730 @@
+UNIT Unit13_rawedit;
+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, Unit15_Classes,
+  Menus, Math;
+
+TYPE
+  TForm13 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    value_viewer: TWrapGrid;
+    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;
+    panel_files: TPanel;
+    opend: TOpenDialog;
+    saved: TSaveDialog;
+    panel_imexport: TPanel;
+    btn_export: TButton;
+    btn_import: TButton;
+    group_file: TGroupBox;
+    list: TListBox;
+    panel_extension: TPanel;
+    lbl_filter: TLabel;
+    combo_extension: TComboBox;
+    edit_filtername: TEdit;
+    check_filtername: TCheckBox;
+    GroupBox1: TGroupBox;
+    list_offset: TListBox;
+    Splitter4: TSplitter;
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE list_offsetClick(Sender: TObject);
+    PROCEDURE LoadRaw(raw_info:TRawInfo);
+    PROCEDURE LoadFileNames;
+    PROCEDURE check_filternameClick(Sender: TObject);
+    PROCEDURE combo_extensionClick(Sender: TObject);
+    PROCEDURE panel_extensionResize(Sender: TObject);
+    PROCEDURE listClick(Sender: TObject);
+    PROCEDURE Recreatelist;
+
+    PROCEDURE FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    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 hexSelectionChanged(Sender: TObject);
+    PROCEDURE hexChange(Sender: TObject);
+    PROCEDURE panel_dataResize(Sender: TObject);
+    PROCEDURE FormResize(Sender: TObject);
+    PROCEDURE FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    PROCEDURE FormCreate(Sender: TObject);
+    PROCEDURE ClearValues;
+    PROCEDURE WriteValues;
+    PROCEDURE SetNewValue(datatype:Word; offset:LongWord; value:String);
+  PRIVATE
+    fileid:LongWord;
+    dat_offset:LongWord;
+    fileid_opened,dat_offset_opened:LongWord;
+  PUBLIC
+  END;
+
+VAR
+  Form13: TForm13;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit;
+
+
+PROCEDURE TForm13.LoadRaw(raw_info:TRawInfo);
+  VAR
+    i:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    IF list_offset.Count=0 THEN BEGIN
+      FOR i:=0 TO list.Count-1 DO BEGIN
+        IF OniDataConnection.ExtractFileID(list.Items.Strings[i])=raw_info.src_id THEN BEGIN
+          list.ItemIndex:=i;
+          listClick(Self);
+          Break;
+        END;
+      END;
+      FOR i:=0 TO list_offset.Count-1 DO BEGIN
+        IF MidStr(list_offset.Items.Strings[i],3,8)=IntToHex(raw_info.src_offset,8) THEN BEGIN
+          list_offset.ItemIndex:=i;
+          Break;
+        END;
+      END;
+    END;
+    SetLength(data,raw_info.raw_size);
+    OniDataConnection.LoadRawFile(raw_info.src_id,raw_info.src_offset,@data[0]);
+    IF Length(data)>0 THEN BEGIN
+      hex.DataSize:=0;
+      hex.DataSize:=raw_info.raw_size;
+      FOR i:=0 TO High(data) DO
+        hex.Data[i]:=data[i];
+      //WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+//      structs.Height:=structs.RowCount*20;
+//      IF structs.Height>120 THEN structs.Height:=120;
+      hexSelectionChanged(Self);
+      fileid_opened:=raw_info.src_id;
+      dat_offset_opened:=raw_info.src_offset;
+      hex.Modified:=False;
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm13.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+    count:LongWord;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('{+IntToStr(dat_header.Files)}+')');
+    exts:=OniDataConnection.GetExtensionsList;
+    FOR i:=0 TO High(RawListHandlers) DO BEGIN
+      count:=Length(OniDataConnection.GetFilesList(RawListHandlers[i].Ext,'',True));
+      combo_extension.Items.Add(RawListHandlers[i].ext+' ('+IntToStr(count)+')');
+    END;
+//    FOR i:=0 TO High(exts) DO
+//      combo_extension.Items.Add(exts[i]);
+    combo_extension.ItemIndex:=0;
+    combo_extensionClick(Self);
+  END;
+
+PROCEDURE TForm13.LoadFileNames;
+  VAR
+    Extension:String;
+    no_zero_bytes:Boolean;
+    pattern:String;
+    files:TStringArray;
+    i:LongWord;
+  BEGIN
+    Extension:=MidStr(combo_extension.Items.Strings[combo_extension.ItemIndex],1,4);
+    pattern:='';
+    IF check_filtername.Checked THEN pattern:=edit_filtername.Text;
+    IF Extension='_All' THEN BEGIN
+      Extension:='';
+      FOR i:=0 TO High(RawListHandlers) DO BEGIN
+        IF Length(Extension)>0 THEN Extension:=Extension+',';
+        Extension:=Extension+RawListHandlers[i].Ext;
+      END;
+    END;
+
+    files:=OniDataConnection.GetFilesList(extension,pattern,TRUE);
+    list.Items.Clear;
+    IF Length(files)>0 THEN
+      FOR i:=0 TO High(files) DO
+        list.Items.Add(files[i]);
+    list_offset.Items.Clear;
+  END;
+
+PROCEDURE TForm13.panel_extensionResize(Sender: TObject);
+  BEGIN
+    combo_extension.Width:=panel_extension.Width-5;
+    edit_filtername.Width:=panel_extension.Width-5;
+  END;
+
+PROCEDURE TForm13.combo_extensionClick(Sender: TObject);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm13.listClick(Sender: TObject);
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+    offsets:TRawList;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        Exit;
+      END;
+    END;
+    ClearValues;
+    hex.DataSize:=0;
+    fileid:=OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]);
+    list_offset.Enabled:=True;
+    IF OniDataConnection.GetFileInfo(fileid).size>0 THEN BEGIN
+      offsets:=OniDataConnection.GetRawList(fileid);
+      list_offset.Items.Clear;
+      IF Length(offsets)>0 THEN BEGIN
+        FOR i:=0 TO High(offsets) DO BEGIN
+          list_offset.Items.Add('0x'+IntToHex(offsets[i].src_offset,8)+', '+IntToStr(offsets[i].raw_size)+' bytes');
+        END;
+      END ELSE BEGIN
+        list_offset.Enabled:=False;
+      END;
+    END ELSE BEGIN
+      list_offset.Enabled:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.list_offsetClick(Sender: TObject);
+  VAR
+    i:LongWord;
+    raw_info:TRawInfo;
+  BEGIN
+    ClearValues;
+    dat_offset:=StrToInt('$'+MidStr(list_offset.Items.Strings[list_offset.ItemIndex],3,8));
+    LoadRaw(OniDataConnection.GetRawInfo(fileid,dat_offset));
+  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 TForm13.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]);
+      11: 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);
+      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 TForm13.ClearValues;
+  VAR
+    i:Byte;
+  BEGIN
+    FOR i:=1 TO value_viewer.RowCount-1 DO BEGIN
+      value_viewer.Cells[1,i]:='';
+    END;
+  END;
+
+PROCEDURE TForm13.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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            Inc(j);
+          END;
+        END ELSE BEGIN
+          FOR j:=0 TO hex.SelCount-1 DO
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              IF hex.Data[hex.selstart+j]>0 THEN
+                str:=str+'.'
+              ELSE
+                Break;
+        END;
+        value_viewer.Cells[1,i]:=str;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    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-190;
+    Self.panel_dataResize(Self);
+//
+    value_viewer.Font.Charset:=AppSettings.CharSet;
+//
+  END;
+
+FUNCTION TForm13.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to .raw-part of file '+OniDataConnection.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;
+          OniDataConnection.UpdateRawFile(fileid_opened,dat_offset_opened,Length(data),@data[0]);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          Result:=True;
+        END;
+      IDNO: Result:=True;
+      IDCANCEL: BEGIN
+          Result:=False;
+        END;
+    END;
+  END;
+
+PROCEDURE TForm13.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN CanClose:=False;
+    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.panel_dataResize(Sender: TObject);
+  BEGIN
+    value_viewer.ColWidths[1]:=value_viewer.Width-value_viewer.ColWidths[0]-28;
+  END;
+
+PROCEDURE TForm13.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+{      WriteStructureInfos(GetStructureInfoId(GetFileInfo(fileid).Extension));
+      WriteValues;
+}    END;
+  END;
+
+PROCEDURE TForm13.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm13.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 TForm13.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm13.panel_imexportResize(Sender: TObject);
+  BEGIN
+    btn_import.Width:=panel_imexport.Width-8;
+    btn_export.Width:=panel_imexport.Width-8;
+  END;
+
+PROCEDURE TForm13.btn_exportClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  BEGIN
+    saved.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(fileid).Extension+'|All files|*.*';
+    saved.DefaultExt:=OniDataConnection.GetFileInfo(fileid).Extension;
+    IF saved.Execute THEN BEGIN
+      fs:=TFileStream.Create(saved.FileName,fmCreate);
+      hex.SaveToStream(fs);
+      fs.Free;
+    END;
+  END;
+
+PROCEDURE TForm13.btn_importClick(Sender: TObject);
+  VAR
+    data:Tdata;
+    fs:TFileStream;
+  BEGIN
+    opend.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(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 TForm13.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm13.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 TForm13.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 TForm13.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 TForm13.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 TForm13.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;
+
+PROCEDURE TForm13.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+END.
Index: /oup/releases/0.32a/src/Unit14_settings.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit14_settings.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit14_settings.dfm	(revision 8)
@@ -0,0 +1,111 @@
+object Form14: TForm14
+  Left = 0
+  Top = 0
+  BorderStyle = bsToolWindow
+  Caption = 'Settings'
+  ClientHeight = 357
+  ClientWidth = 321
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  OldCreateOrder = False
+  Position = poMainFormCenter
+  OnCloseQuery = FormCloseQuery
+  OnShow = FormShow
+  PixelsPerInch = 96
+  TextHeight = 13
+  object label_charset: TLabel
+    Left = 8
+    Top = 39
+    Width = 145
+    Height = 26
+    AutoSize = False
+    Caption = 'CharSet for displaying strings in ValueViewer/StructViewer:'
+    WordWrap = True
+  end
+  object check_filesashex: TCheckBox
+    Left = 8
+    Top = 8
+    Width = 145
+    Height = 17
+    Caption = 'Show filenumbers as Hex'
+    TabOrder = 0
+  end
+  object btn_ok: TButton
+    Left = 8
+    Top = 319
+    Width = 57
+    Height = 23
+    Caption = 'OK'
+    Default = True
+    TabOrder = 1
+    OnClick = btn_okClick
+  end
+  object btn_cancel: TButton
+    Left = 120
+    Top = 319
+    Width = 57
+    Height = 23
+    Cancel = True
+    Caption = 'Cancel'
+    TabOrder = 2
+    OnClick = btn_cancelClick
+  end
+  object btn_register_oldb: TButton
+    Left = 8
+    Top = 184
+    Width = 169
+    Height = 25
+    Caption = 'Register .oldb files with OUP'
+    TabOrder = 3
+    OnClick = btn_register_oldbClick
+  end
+  object btn_register_opf: TButton
+    Left = 8
+    Top = 215
+    Width = 169
+    Height = 25
+    Caption = 'Register .opf files with OUP'
+    TabOrder = 4
+    OnClick = btn_register_opfClick
+  end
+  object btn_register_dat: TButton
+    Left = 8
+    Top = 153
+    Width = 169
+    Height = 25
+    Caption = 'Register .dat files with OUP'
+    TabOrder = 5
+    OnClick = btn_register_datClick
+  end
+  object combo_charset: TComboBox
+    Left = 160
+    Top = 40
+    Width = 156
+    Height = 21
+    ItemHeight = 13
+    TabOrder = 6
+    Text = 'DEFAULT_CHARSET'
+    Items.Strings = (
+      'default - 1'
+      'Arabic - 178'
+      'Baltic - 186'
+      'ChineseBig5 - 136'
+      'EastEurope - 238'
+      'Greek - 161'
+      'Russian - 204'
+      'Thai - 222'
+      'Turkish - 162')
+  end
+  object check_hideunused: TCheckBox
+    Left = 8
+    Top = 79
+    Width = 209
+    Height = 17
+    Caption = 'Hide "Unused" data in StructureViewer'
+    TabOrder = 7
+  end
+end
Index: /oup/releases/0.32a/src/Unit14_settings.pas
===================================================================
--- /oup/releases/0.32a/src/Unit14_settings.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit14_settings.pas	(revision 8)
@@ -0,0 +1,167 @@
+unit Unit14_settings;
+interface
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls, StrUtils, Grids, Wrapgrid;
+
+type
+  TForm14 = class(TForm)
+    check_filesashex: TCheckBox;
+    btn_ok: TButton;
+    btn_cancel: TButton;
+    btn_register_oldb: TButton;
+    btn_register_opf: TButton;
+    btn_register_dat: TButton;
+    label_charset: TLabel;
+    combo_charset: TComboBox;
+    check_hideunused: TCheckBox;
+    procedure btn_register_opfClick(Sender: TObject);
+    procedure btn_register_oldbClick(Sender: TObject);
+    procedure btn_register_datClick(Sender: TObject);
+    procedure btn_cancelClick(Sender: TObject);
+    procedure btn_okClick(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+    procedure FormShow(Sender: TObject);
+    function RegisterExtension(ext:String):Integer;
+  private
+  public
+  end;
+
+var
+  Form14: TForm14;
+
+implementation
+{$R *.dfm}
+uses
+  Unit1_main, Unit3_data, ftypesAPI;
+
+function ExtensionRegistered(ext:String; var RegisteredAs:String):Boolean;
+  var
+    ftr:TFileTypeRegistration;
+  begin
+    ftr:=TFileTypeRegistration.Create;
+    if(ftr <> nil) then begin
+      try
+        RegisteredAs:=ftr.GetInternalKey(ext);
+        if RegisteredAs<>'' then
+          Result:=True
+        else
+          Result:=False;
+      finally
+        ftr.Free;
+      end;
+    end;
+  end;
+
+function TForm14.RegisterExtension(ext:String):Integer;
+  var
+    ftr:TFileTypeRegistration;
+    temps:String;
+    warnmsg:String;
+  begin
+    Result:=-1;
+    if ExtensionRegistered(ext,temps) then begin
+      if temps<>'ONI'+ext then begin
+        warnmsg:=ext+'-files are not registered to OUP but as "'+temps+'"-files.'+#13+#10+
+                 'Do you really want to unregister'+ext+'-files?';
+        if MessageBox(Self.Handle, PChar(warnmsg),PChar('Warning'),MB_YESNO)=ID_NO then
+          Exit;
+      end;
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then
+        try
+          if not ftr.UnregisterExtension(ext) then
+            ShowMessage('Could not unregister '+ext+'-files')
+          else
+            Result:=2;
+        finally
+          ftr.Free;
+        end;
+    end else begin
+      ftr:=TFileTypeRegistration.Create;
+      if ftr<>nil then begin
+        try
+          if ftr.RegisterType(ext,'ONI'+ext,'ONI '+ext+'-file',Application.EXEname+',1') then begin
+            ftr.AddHandler('open','"'+Application.EXEname+'" '+MidStr(ext,2,Length(ext)-1)+' "%1"');
+            ftr.SetDefaultHandler;
+            Result:=1;
+          end;
+        finally
+          ftr.Free;
+        end;
+      end;
+    end;
+  end;
+
+procedure TForm14.btn_cancelClick(Sender: TObject);
+  begin
+    Self.Close;
+  end;
+
+procedure TForm14.btn_okClick(Sender: TObject);
+  begin
+    AppSettings.FilenumbersAsHex:=check_filesashex.Checked;
+    AppSettings.CharSet:=StrToInt(MidStr(combo_charset.Items.Strings[combo_charset.ItemIndex],Pos(' ',combo_charset.Items.Strings[combo_charset.ItemIndex])+3,Length(combo_charset.Items.Strings[combo_charset.ItemIndex])-Pos(' ',combo_charset.Items.Strings[combo_charset.ItemIndex])-2));
+    AppSettings.HideUnusedData:=check_hideunused.Checked;
+
+    Self.Close;
+  end;
+
+procedure TForm14.btn_register_datClick(Sender: TObject);
+  begin
+    case RegisterExtension('.dat') of
+      2: btn_register_dat.Caption:='Register .dat files with OUP';
+      1: btn_register_dat.Caption:='Unregister .dat files';
+    end;
+  end;
+
+procedure TForm14.btn_register_oldbClick(Sender: TObject);
+  begin
+    case RegisterExtension('.oldb') of
+      2: btn_register_oldb.Caption:='Register .oldb files with OUP';
+      1: btn_register_oldb.Caption:='Unregister .oldb files';
+    end;
+  end;
+
+procedure TForm14.btn_register_opfClick(Sender: TObject);
+  begin
+    case RegisterExtension('.opf') of
+      2: btn_register_opf.Caption:='Register .opf files with OUP';
+      1: btn_register_opf.Caption:='Unregister .opf files';
+    end;
+  end;
+
+procedure TForm14.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+  begin
+    CanClose:=False;
+    Self.Visible:=False;
+    Form1.Enabled:=True;
+    Form1.SetFocus;
+  end;
+
+procedure TForm14.FormShow(Sender: TObject);
+  var
+    temps:String;
+    i:Byte;
+  begin
+    if ExtensionRegistered('.dat',temps) then
+      btn_register_dat.Caption:='Unregister .dat files'
+    else
+      btn_register_dat.Caption:='Register .dat files with OUP';
+    if ExtensionRegistered('.oldb',temps) then
+      btn_register_oldb.Caption:='Unregister .oldb files'
+    else
+      btn_register_oldb.Caption:='Register .oldb files with OUP';
+    if ExtensionRegistered('.opf',temps) then
+      btn_register_opf.Caption:='Unregister .opf files'
+    else
+      btn_register_opf.Caption:='Register .opf files with OUP';
+    check_filesashex.Checked:=AppSettings.FilenumbersAsHex;
+    check_hideunused.Checked:=AppSettings.HideUnusedData;
+
+    for i:=0 to combo_charset.Items.Count-1 do
+      if StrToInt(MidStr(combo_charset.Items.Strings[i],Pos(' ',combo_charset.Items.Strings[i])+3,Length(combo_charset.Items.Strings[i])-Pos(' ',combo_charset.Items.Strings[i])-2))=AppSettings.CharSet then
+        combo_charset.ItemIndex:=i;
+  end;
+
+end.
Index: /oup/releases/0.32a/src/Unit15_Classes.pas
===================================================================
--- /oup/releases/0.32a/src/Unit15_Classes.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit15_Classes.pas	(revision 8)
@@ -0,0 +1,1056 @@
+unit Unit15_Classes;
+interface
+uses Unit3_data, Unit9_data_structures, Classes, SysUtils, StrUtils, Dialogs, ABSDecUtil, ABSMain, DB;
+
+
+type
+  TOniData = class
+    private
+      FFileName:String;
+      FLevelInfo:TLevelInfo;
+      FBackend:Integer;
+      Fos_mac:Boolean;
+    protected
+    public
+      property FileName:String read FFileName write FFileName; 
+      property Backend:Integer read FBackend write FBackend;
+      property OSisMac:Boolean read Fos_mac write Fos_mac;
+      property LevelInfo:TLevelinfo read FLevelInfo write FLevelInfo;
+
+      constructor Create(filename:String; var Result:Boolean); virtual; abstract;
+      procedure Close; virtual; abstract;
+
+      function GetFileInfo(fileid:LongWord):TFileInfo; virtual; abstract;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; virtual; abstract;
+      function GetFilesCount:LongWord; virtual; abstract;
+      function GetExtensionsList:TStringArray; virtual; abstract;
+      function GetExtendedExtensionsList:TExtensionsMap; virtual; abstract;
+      function ExtractFileID(name:String):Integer;
+      function GetFileIDByName(name:String):Integer;
+
+      function LoadDatFile(fileid:LongWord):Tdata; virtual; abstract;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); virtual; abstract;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); virtual; abstract;
+
+      function GetRawList(fileid:LongWord):TRawList; virtual; abstract;
+      function GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); virtual; abstract;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); virtual; abstract;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); virtual; abstract;
+      function AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; virtual; abstract;//Returns new Address
+    published
+  end;
+
+  TOniDataDat = class(TOniData)
+    private
+      Fdat_file:TFileStream;
+      Fraw_file:TFileStream;
+      Fsep_file:TFileStream;
+      Fdat_header:THeader;
+      Fdat_filesmap:TFilesMap;
+      Fdat_files:TFiles;
+      Fdat_namedfilesmap:TNamedFilesMap;
+      Fdat_extensionsmap:TExtensionsMap;
+      FUnloadWhenUnused:Boolean;
+      FDatOpened:Boolean;
+      FRawOpened:Boolean;
+      FSepOpened:Boolean;
+    protected
+    public
+      property UnloadWhenUnused:Boolean read FUnloadWhenUnused write FUnloadWhenUnused;
+
+      constructor Create(DatFilename:String; var Result:Boolean); override;
+      procedure Close; override;
+
+      function GetFileInfo(fileid:LongWord):TFileInfo; override;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; override;
+      function GetFilesCount:LongWord; override;
+      function GetExtensionsList:TStringArray; override;
+      function GetExtendedExtensionsList:TExtensionsMap; override;
+
+      function LoadDatFile(fileid:LongWord):Tdata; override;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); override;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+
+      procedure LoadRawOffset(loc_sep:Boolean; raw_addr,size:LongWord; target:Pointer);
+      function GetRawList(fileid:LongWord):TRawList; override;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); override;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); override;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      function AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; override;//Returns new Address
+    published
+  end;
+
+  TOniDataADB = class(TOniData)
+    private
+      FDatabase:TABSDatabase;
+      FQuery:TABSQuery;
+    protected
+    public
+      constructor Create(OLDBFilename:String; var Result:Boolean); override;
+      procedure Close; override;
+
+//      function GetDatLinks(srcid:LongWord):TDatLinks;
+      function GetFileInfo(fileid:LongWord):TFileInfo; override;
+      function GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray; override;
+      function GetFilesCount:LongWord; override;
+      function GetExtensionsList:TStringArray; override;
+      function GetExtendedExtensionsList:TExtensionsMap; override;
+      function GetNamedFilesMap:TNamedFilesMap;
+
+      function LoadDatFile(fileid:LongWord):Tdata; override;
+      procedure UpdateDatFile(fileid:LongWord; data:Tdata); override;
+      procedure LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+      procedure UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer); override;
+
+      function GetRawList(fileid:LongWord):TRawList; override;
+      procedure LoadRawFile(fileid,dat_offset:LongWord; target:Pointer); override;
+      procedure UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer); override;
+      procedure LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+      procedure UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer); override;
+    published
+  end;
+
+
+const
+  ODB_None=-1;
+  ODB_Dat=0;
+  ODB_ADB=1;
+
+var
+  OniDataConnection:TOniData;
+
+function CreateDataConnection(filename:String; backend:Integer):Boolean;
+procedure CloseDataConnection;
+
+
+
+
+implementation
+uses Unit2_Functions;
+
+
+
+(*
+  Implementation of  TOniData
+*)
+
+function TOniData.GetFileIDByName(name:String):Integer;
+  var
+    files:TStringArray;
+    i: Integer;
+  begin
+    Result:=-1;
+    files:=Self.GetFilesList('',name,false);
+    if Length(files)>0 then
+      for i:=0 to High(files) do
+        if Pos(name,files[i])=Pos('-',files[i])+1 then begin
+//        if MidStr(files[i],Pos('-',files[i])+1,Length(files[i])-Pos('-',files[i])-5)=name then begin
+          Result:=Self.ExtractFileID(files[i]);
+          Break;
+        end;
+  end;
+
+function TOniData.ExtractFileID(name:String):Integer;
+  begin
+    if name[5]='-' then
+      Result:=HexToLong(MidStr(name,1,4))
+    else
+      Result:=StrToInt(MidStr(name,1,5));
+  end;
+
+function TOniData.GetRawInfo(fileid,dat_offset:LongWord):TRawInfo;
+  var
+    i:LongWord;
+    raw_list:TRawList;
+  begin
+    raw_list:=Self.GetRawList(fileid);
+    Result.src_id:=0;
+    Result.src_offset:=0;
+    Result.raw_addr:=0;
+    Result.raw_size:=0;
+    for i:=0 to High(raw_list) do begin
+      if raw_list[i].src_offset=dat_offset then begin
+        Result.src_id:=fileid;
+        Result.src_offset:=raw_list[i].src_offset;
+        Result.raw_addr:=raw_list[i].raw_addr;
+        Result.raw_size:=raw_list[i].raw_size;
+        Result.loc_sep:=raw_list[i].loc_sep;
+        Break;
+      end;
+    end;
+  end;
+
+
+
+
+
+
+
+(*
+================================================================================
+                      Implementation of  TOniDataDat
+*)
+
+constructor TOniDataDat.Create(DatFilename:String; var Result:Boolean);
+  const
+    header_ident1_pc: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_ident1_mac:Array[0..$13] of Byte=
+        ($61,$30,$C1,$23,$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);
+  var
+    i:LongWord;
+    header_pc,header_mac:Boolean;
+  begin
+    FUnloadWhenUnused:=True;
+    FDatOpened:=False;
+    FRawOpened:=False;
+    if not FileExists(DatFilename) then begin
+      ShowMessage('File doesn''t exist!!!');
+      Result:=False;
+      Exit;
+    end;
+    FFileName:=DatFilename;
+    Fdat_file:=TFileStream.Create(FFileName, fmOpenRead);
+    Fdat_file.Read(Fdat_header,SizeOf(Fdat_header));
+    header_pc:=True;
+    header_mac:=True;
+    for i:=0 to High(Fdat_header.Ident) do begin
+      FLevelInfo.Ident[i]:=Fdat_header.Ident[i];
+      if Fdat_header.Ident[i]<>header_ident1_pc[i] then
+        header_pc:=False;
+      if Fdat_header.Ident[i]<>header_ident1_mac[i] then
+        header_mac:=False;
+    end;
+    if not (header_pc xor header_mac) then begin
+      Result:=False;
+      Exit;
+    end else begin
+      if (header_pc and not header_mac) then
+        Fos_mac:=False
+      else
+        Fos_mac:=True;
+    end;
+    SetLength(Fdat_filesmap,Fdat_header.Files);
+    SetLength(Fdat_files,Fdat_header.Files);
+    for i:=0 to Fdat_header.Files-1 do
+      Fdat_file.Read(Fdat_filesmap[i],SizeOf(Fdat_filesmap[i]));
+    for i:=0 to Fdat_header.Files-1 do begin
+      Fdat_files[i].Extension:=Fdat_filesmap[i].Extension;
+      Fdat_files[i].Extension:=ReverseString(Fdat_files[i].Extension);
+      Fdat_files[i].Size:=Fdat_filesmap[i].FileSize;
+      Fdat_files[i].FileType:=Fdat_filesmap[i].FileType;
+      Fdat_files[i].DatAddr:=Fdat_filesmap[i].DataAddr-8+Fdat_header.DataAddr;
+      if (Fdat_filesmap[i].FileType and $01)=0 then begin
+        Fdat_file.Seek(Fdat_filesmap[i].NameAddr+Fdat_header.NamesAddr,soFromBeginning);
+        SetLength(Fdat_files[i].Name,100);
+        Fdat_file.Read(Fdat_files[i].Name[1],100);
+        Fdat_files[i].Name:=MidStr(Fdat_files[i].Name,1+4,Pos(#0,Fdat_files[i].Name)-1-4);
+      end else begin
+        Fdat_files[i].Name:='';
+      end;
+      Fdat_files[i].FileName:=FormatNumber(i,5,'0')+'-'+Fdat_files[i].Name+'.'+Fdat_files[i].Extension;
+      Fdat_files[i].FileNameHex:=IntToHex(i,4)+'-'+Fdat_files[i].Name+'.'+Fdat_files[i].Extension;
+    end;
+    Fdat_file.Seek($40+Fdat_header.Files*$14,soFromBeginning);
+    SetLength(Fdat_namedfilesmap,Fdat_header.NamedFiles);
+    for i:=0 to Fdat_header.NamedFiles-1 do
+      Fdat_file.Read(Fdat_namedfilesmap[i],SizeOf(Fdat_namedfilesmap[i]));
+
+    Fdat_file.Seek($40+Fdat_header.Files*$14+Fdat_header.NamedFiles*$8,soFromBeginning);
+    SetLength(Fdat_extensionsmap,Fdat_header.Extensions);
+    for i:=0 to Fdat_header.Extensions-1 do
+      Fdat_file.Read(Fdat_extensionsmap[i],SizeOf(Fdat_extensionsmap[i]));
+
+    Fdat_file.Seek(Fdat_files[0].DatAddr+7,soFromBeginning);
+    Fdat_file.Read(FLevelInfo.LevelNumber,1);
+    FLevelInfo.LevelNumber:=FLevelInfo.LevelNumber DIV 2;
+
+    Fdat_file.Free;
+
+    Result:=True;
+    FBackend:=ODB_Dat;
+  end;
+
+procedure TOniDataDat.Close;
+  begin
+    if not FUnloadWhenUnused and FDatOpened then
+      Fdat_file.Free;
+    if not FUnloadWhenUnused and FRawOpened then
+      Fraw_file.Free;
+    if not FUnloadWhenUnused and FSepOpened then
+      Fsep_file.Free;
+    Self.Free;
+  end;
+
+
+
+function TOniDataDat.GetFileInfo(fileid:LongWord):TFileInfo;
+  begin
+    if fileid<Self.GetFilesCount then
+      Result:=Fdat_files[fileid]
+    else
+      Result.ID:=-1;
+  end;
+
+function TOniDataDat.GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    for i:=0 to Fdat_header.Files-1 do begin
+      if ( (Length(ext)=0) or (Pos(Fdat_files[i].Extension,ext)>0) ) and
+          ( (Length(pattern)=0) or (Pos(UpperCase(pattern),UpperCase(Fdat_files[i].Name))>0) ) then begin
+          if (NoEmptyFiles=false) or ((Fdat_files[i].FileType and $02)=0) then begin
+            SetLength(Result,Length(Result)+1);
+            if AppSettings.FilenumbersAsHex then
+              Result[High(Result)]:=Fdat_files[i].FileNameHex
+            else
+              Result[High(Result)]:=Fdat_files[i].FileName;
+          end;
+      end;
+    end;
+  end;
+
+function TOniDataDat.GetFilesCount:LongWord;
+  begin
+    Result:=Fdat_header.Files;
+  end;
+
+function TOniDataDat.GetExtensionsList:TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,Fdat_header.Extensions);
+    for i:=0 to Fdat_header.Extensions-1 do begin
+      with Fdat_extensionsmap[i] do begin
+        Result[i]:=Extension[3]+Extension[2]+Extension[1]+Extension[0]+' ('+IntToStr(ExtCount)+')';
+      end;
+    end;
+  end;
+
+function TOniDataDat.GetExtendedExtensionsList:TExtensionsMap;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,Fdat_header.Extensions);
+    for i:=0 to Fdat_header.Extensions-1 do begin
+      Result[i]:=Fdat_extensionsmap[i];
+    end;
+  end;
+
+
+function TOniDataDat.LoadDatFile(fileid:LongWord):Tdata;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      if FUnloadWhenUnused or not FDatOpened then
+        Fdat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      Fdat_file.Seek(Fdat_files[fileid].DatAddr,soFromBeginning);
+      SetLength(Result,Fdat_files[fileid].Size);
+      Fdat_file.Read(Result[0],Fdat_files[fileid].Size);
+      if UnloadWhenUnused then
+        Fdat_file.Free
+      else
+        FDatOpened:=True;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateDatFile(fileid:LongWord; data:Tdata);
+  begin
+    if fileid<Self.GetFilesCount then begin
+      if FUnloadWhenUnused or not FDatOpened then
+        Fdat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      Fdat_file.Seek(Fdat_files[fileid].DatAddr,soFromBeginning);
+      Fdat_file.Write(data[0],Length(data));
+      if UnloadWhenUnused then
+        Fdat_file.Free
+      else
+        FDatOpened:=True;
+    end;
+  end;
+
+procedure TOniDataDat.LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  begin
+    if fileid<Self.GetFilesCount then begin
+      if FUnloadWhenUnused or not FDatOpened then
+        Fdat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      Fdat_file.Seek(Fdat_files[fileid].DatAddr+offset,soFromBeginning);
+      Fdat_file.Read(target^,size);
+      if UnloadWhenUnused then
+        Fdat_file.Free
+      else
+        FDatOpened:=True;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  begin
+    if fileid<Self.GetFilesCount then begin
+      if FUnloadWhenUnused or not FDatOpened then
+        Fdat_file:=TFileStream.Create(FFileName, fmOpenReadWrite);
+      Fdat_file.Seek(Fdat_files[fileid].DatAddr+offset,soFromBeginning);
+      Fdat_file.Write(target^,size);
+      if UnloadWhenUnused then
+        Fdat_file.Free
+      else
+        FDatOpened:=True;
+    end;
+  end;
+
+
+
+function TOniDataDat.GetRawList(fileid:LongWord):TRawList;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    for i:=0 to High(RawListHandlers) do
+      if UpperCase(RawListHandlers[i].Ext)=UpperCase(Fdat_files[fileid].extension) then
+        if RawListHandlers[i].needed then begin
+          Result:=RawListHandlers[i].Handler(fileid);
+          Break;
+        end else
+          Break;
+  end;
+
+procedure TOniDataDat.LoadRawOffset(loc_sep:Boolean; raw_addr,size:LongWord; target:Pointer);
+  begin
+    if not loc_sep then begin
+      if FUnloadWhenUnused or not FRawOpened then
+        Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+      if raw_addr<=Fraw_file.Size then begin
+        Fraw_file.Seek(raw_addr,soFromBeginning);
+        Fraw_file.Read(target^,size);
+      end;
+      if UnloadWhenUnused then
+        Fraw_file.Free
+      else
+        FRawOpened:=True
+    end else begin
+      if FUnloadWhenUnused or not FSepOpened then
+        Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+      if raw_addr<=Fsep_file.Size then begin
+        Fsep_file.Seek(raw_addr,soFromBeginning);
+        Fsep_file.Read(target^,size);
+      end;
+      if UnloadWhenUnused then
+        Fsep_file.Free
+      else
+        FSepOpened:=True;
+    end;
+  end;
+
+procedure TOniDataDat.LoadRawFile(fileid,dat_offset:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then begin
+        if FUnloadWhenUnused or not FRawOpened then
+          Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+        Fraw_file.Seek(raw_info.raw_addr,soFromBeginning);
+        Fraw_file.Read(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fraw_file.Free
+        else
+          FRawOpened:=True
+      end else begin
+        if FUnloadWhenUnused or not FSepOpened then
+          Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+        Fsep_file.Seek(raw_info.raw_addr,soFromBeginning);
+        Fsep_file.Read(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fsep_file.Free
+        else
+          FSepOpened:=True;
+      end;
+    end;
+  end;
+
+procedure TOniDataDat.UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then begin
+        if FUnloadWhenUnused or not FRawOpened then
+          Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+        Fraw_file.Seek(raw_info.raw_addr,soFromBeginning);
+        Fraw_file.Write(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fraw_file.Free
+        else
+          FRawOpened:=True
+      end else begin
+        if FUnloadWhenUnused or not FSepOpened then
+          Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+        Fsep_file.Seek(raw_info.raw_addr,soFromBeginning);
+        Fsep_file.Write(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fsep_file.Free
+        else
+          FSepOpened:=True;
+      end;
+    end;
+  end;
+
+procedure TOniDataDat.LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+    data:Tdata;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      SetLength(data, raw_info.raw_size);
+      Self.LoadRawFile(fileid,dat_offset,@data[0]);
+      mem:=TMemoryStream.Create;
+      mem.Write(data[offset],size);
+      mem.Read(target^,size);
+      mem.Free;  
+    end;
+  end;
+
+procedure TOniDataDat.UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    raw_info:TRawInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      raw_info:=Self.GetRawInfo(fileid,dat_offset);
+      if not raw_info.loc_sep then begin
+        if FUnloadWhenUnused or not FRawOpened then
+          Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+        Fraw_file.Seek(raw_info.raw_addr+offset,soFromBeginning);
+        Fraw_file.Write(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fraw_file.Free
+        else
+          FRawOpened:=True
+      end else begin
+        if FUnloadWhenUnused or not FSepOpened then
+          Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+        Fsep_file.Seek(raw_info.raw_addr+offset,soFromBeginning);
+        Fsep_file.Write(target^,raw_info.raw_size);
+        if UnloadWhenUnused then
+          Fsep_file.Free
+        else
+          FSepOpened:=True;
+      end;
+    end;
+  end;
+
+function TOniDataDat.AppendRawFile(loc_sep:Boolean; size:LongWord; target:Pointer):LongWord; //Returns new Address
+  begin
+    if not loc_sep then begin
+      if FUnloadWhenUnused or not FRawOpened then
+        Fraw_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.raw'),fmOpenReadWrite);
+      Result:=Fraw_file.Size;
+      Fraw_file.Seek(0,soFromEnd);
+      Fraw_file.Write(target^,size);
+      if UnloadWhenUnused then
+        Fraw_file.Free
+      else
+        FRawOpened:=True
+    end else begin
+      if FUnloadWhenUnused or not FSepOpened then
+        Fsep_file:=TFileStream.Create(AnsiReplaceStr(FFileName,'.dat','.sep'),fmOpenReadWrite);
+      Result:=Fsep_file.Size;
+      Fsep_file.Seek(0,soFromEnd);
+      Fsep_file.Write(target^,size);
+      if UnloadWhenUnused then
+        Fsep_file.Free
+      else
+        FSepOpened:=True;
+    end;
+  end;
+
+
+
+
+
+
+
+
+
+  
+
+(*
+================================================================================
+                     Implementation of  TOniDataADB
+*)
+
+constructor TOniDataADB.Create(OLDBFilename:String; var Result:Boolean);
+  var
+    i,j:Byte;
+    temps:String;
+  begin
+    if not FileExists(OLDBFilename) then begin
+      ShowMessage('File doesn''t exist!!!');
+      Result:=False;
+      Exit;
+    end;
+    FFileName:=OLDBFilename;
+    FDatabase:=TABSDatabase.Create(nil);
+    FDatabase.DatabaseName:='OLDBcon';
+    FDatabase.DatabaseFileName:=OLDBFilename;
+    FDatabase.Open;
+    FQuery:=TABSQuery.Create(FDatabase);
+    FQuery.DatabaseName:='OLDBcon';
+    FQuery.SQL.Text:='SELECT [name],[value] FROM globals ORDER BY [name] ASC';
+    FQuery.Open;
+    FQuery.First;
+    repeat
+      if FQuery.FieldByName('name').AsString='dbversion' then begin
+        if FQuery.FieldByName('value').AsString<>DBversion then begin
+          ShowMessage('Database-file '+#13+#10+
+                      '"'+OLDBFilename+'"'+#13+#10+
+                      'has wrong version. (Required: '+DBversion+'; found: '+
+                        FQuery.FieldByName('value').AsString+')');
+          FQuery.Close;
+          Result:=False;
+          Exit;
+        end;
+      end;
+      if FQuery.FieldByName('name').AsString='lvl' then begin
+        FLevelInfo.LevelNumber:=StrToInt(FQuery.FieldByName('value').AsString);
+      end;
+      if FQuery.FieldByName('name').AsString='ident' then begin
+        temps:=FQuery.FieldByName('value').AsString;
+        for i:=0 to High(FLevelInfo.Ident) do begin
+          j:=i*2+1;
+          case temps[j] of
+            '0'..'9': FLevelInfo.Ident[i]:=Ord(temps[j])-48;
+            'A'..'F': FLevelInfo.Ident[i]:=Ord(temps[j])-55;
+          end;
+          FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]*16;
+          case temps[j+1] of
+            '0'..'9': FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]+Ord(temps[j+1])-48;
+            'A'..'F': FLevelInfo.Ident[i]:=FLevelInfo.Ident[i]+Ord(temps[j+1])-55;
+          end;
+        end;
+      end;
+      if FQuery.FieldByName('name').AsString='ident' then begin
+        temps:=FQuery.FieldByName('value').AsString;
+        Fos_mac:=temps='MAC';
+      end;
+      FQuery.Next;
+    until FQuery.EoF;
+    FQuery.Close;
+
+    Result:=True;
+    FBackend:=ODB_ADB;
+  end;
+
+procedure TOniDataADB.Close;
+  begin
+    FDatabase.Close;
+    FDatabase.Free;
+    Self.Free;
+  end;
+
+
+
+function TOniDataADB.GetFileInfo(fileid:LongWord):TFileInfo;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT * FROM datfiles WHERE id='+IntToStr(fileid)+' ORDER BY id ASC;';
+      FQuery.Open;
+      if FQuery.RecordCount=1 then begin
+        FQuery.First;
+        Result.ID:=FQuery.FieldByName('id').AsInteger;
+        Result.Name:=FQuery.FieldByName('name').AsString;
+        Result.Extension:=FQuery.FieldByName('extension').AsString;
+        Result.FileName:=FormatNumber(Result.ID,5,'0')+'-'+Result.Name+'.'+Result.Extension;
+        Result.Size:=FQuery.FieldByName('size').AsInteger;
+        Result.FileType:=HexToLong(FQuery.FieldByName('contenttype').AsString);
+        Result.DatAddr:=0;
+        Result.opened:=False;
+      end;
+      FQuery.Close;
+    end else begin
+      Result.ID:=-1;
+    end;
+  end;
+
+function TOniDataADB.GetFilesList(ext:String; pattern:String; NoEmptyFiles:Boolean):TStringArray;
+  var
+    i:LongWord;
+    where:String;
+    where_ext:String;
+  begin
+    where:='';
+    if Length(ext)>0 then begin
+      if Length(where)>0 then
+        where:=where+' AND ';
+      if Pos(',',ext)>0 then begin
+        i:=1;
+        where_ext:='';
+        while i<Length(ext) do begin
+          if Length(where_ext)>0 then
+            where_ext:=where_ext+' OR ';
+          where_ext:=where_ext+'(extension="'+MidStr(ext,i,4)+'")';
+          i:=i+5;
+        end;
+        where:=where+'('+where_ext+')';
+      end else begin
+        where:=where+'(extension="'+ext+'")';
+      end;
+    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;
+    FQuery.SQL.Text:='SELECT id,name,extension FROM datfiles'+where+' ORDER BY id ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i]:=FormatNumber(FQuery.FieldByName('id').AsInteger,5,'0')+'-'+FQuery.FieldByName('name').AsString+'.'+FQuery.FieldByName('extension').AsString;
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetFilesCount:LongWord;
+  begin
+    FQuery.SQL.Text:='SELECT Count(*) AS cnumber FROM datfiles;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      Result:=FQuery.FieldByName('cnumber').AsInteger;
+    end else Result:=0;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetExtensionsList:TStringArray;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    FQuery.SQL.Text:='SELECT extension,count(extension) AS x FROM datfiles GROUP BY extension ORDER BY extension ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i]:=FQuery.FieldByName('extension').AsString+' ('+IntToStr(FQuery.FieldByName('x').AsInteger)+')';
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetExtendedExtensionsList:TExtensionsMap;
+  var
+    i,j:LongWord;
+    temps:String;
+    data:Tdata;
+  begin
+    SetLength(Result,0);
+    FQuery.SQL.Text:='SELECT ext,ident FROM extlist ORDER BY ext ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        temps:=FQuery.FieldByName('ext').AsString;
+        for j:=0 to 3 do Result[i].Extension[j]:=temps[4-j];
+        data:=DecodeHexString(FQuery.FieldByName('ident').AsString);
+        for j:=0 to 7 do Result[i].Ident[j]:=data[j];
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+
+function TOniDataADB.GetNamedFilesMap:TNamedFilesMap;
+  var
+    i:LongWord;
+    temp:Integer;
+    temps:String;
+    temparray:Array of Record
+        id:Integer;
+        fullname:String[50];
+      end;
+  begin
+    SetLength(temparray,0);
+    FQuery.SQL.Text:='SELECT id,(extension+name) AS xname FROM datfiles WHERE Length(name)>0 ORDER BY extension,name ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      repeat
+        temp:=FQuery.FieldByName('id').AsInteger;
+        temps:=FQuery.FieldByName('xname').AsString;
+
+        SetLength(temparray,Length(temparray)+1);
+        if Length(temparray)>1 then begin
+          for i:=High(temparray)-1 downto 0 do begin
+            if StringSmaller(temps,temparray[i].fullname) then begin
+              temparray[i+1]:=temparray[i];
+              if i=0 then begin
+                temparray[i].id:=temp;
+                temparray[i].fullname:=temps;
+              end;
+            end else begin
+              temparray[i+1].id:=temp;
+              temparray[i+1].fullname:=temps;
+              Break;
+            end;
+          end;
+        end else begin
+          temparray[0].id:=temp;
+          temparray[0].fullname:=temps;
+        end;
+        FQuery.Next;
+      until FQuery.Eof;
+    end;
+    FQuery.Close;
+    SetLength(Result,Length(temparray));
+    for i:=0 to High(temparray) do begin
+      Result[i].FileNumber:=temparray[i].id;
+      Result[i].blubb:=0;
+    end;
+  end;
+
+
+
+function TOniDataADB.LoadDatFile(fileid:LongWord):Tdata;
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';';
+      FQuery.Open;
+      if FQuery.RecordCount>0 then begin
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        SetLength(Result,mem.Size);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(Result[0],mem.Size);
+        mem.Free;
+      end;
+      FQuery.Close;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateDatFile(fileid:LongWord; data:Tdata);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE datfiles SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE id='+IntToStr(fileid)+';';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+procedure TOniDataADB.LoadDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM datfiles WHERE id='+IntToStr(fileid)+';';
+      FQuery.Open;
+      IF FQuery.RecordCount>0 THEN BEGIN
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        mem.Seek(offset,soFromBeginning);
+        mem.Read(target^,size);
+        mem.Free;
+      END;
+      FQuery.Close;
+    END;
+  END;
+
+procedure TOniDataADB.UpdateDatFilePart(fileid,offset,size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+    data:Tdata;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      data:=Self.LoadDatFile(fileid);
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(offset,soFromBeginning);
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE datfiles SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE id='+IntToStr(fileid)+';';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+
+
+function TOniDataADB.GetRawList(fileid:LongWord):TRawList;
+  var
+    i:LongWord;
+  begin
+    SetLength(Result,0);
+    FQuery.SQL.Text:='SELECT [src_link_offset],[size],[sep] FROM rawmap WHERE [src_id]='+IntToStr(fileid)+' ORDER BY src_link_offset ASC;';
+    FQuery.Open;
+    if FQuery.RecordCount>0 then begin
+      FQuery.First;
+      SetLength(Result,FQuery.RecordCount);
+      i:=0;
+      repeat
+        Result[i].src_id:=fileid;
+        Result[i].src_offset:=FQuery.FieldByName('src_link_offset').AsInteger;
+        Result[i].raw_addr:=0;
+        Result[i].raw_size:=FQuery.FieldByName('size').AsInteger;
+        Result[i].loc_sep:=FQuery.FieldByName('sep').AsBoolean;
+        Inc(i);
+        FQuery.Next;
+      until FQuery.EOF;
+    end;
+    FQuery.Close;
+  end;
+  
+procedure TOniDataADB.LoadRawFile(fileid,dat_offset:LongWord; target:Pointer);
+  var
+    mem:TStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      FQuery.SQL.Text:='SELECT data FROM rawmap WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.Open;
+      if FQuery.RecordCount>0 then begin
+        mem:=FQuery.CreateBlobStream(FQuery.FieldByName('data'),bmRead);
+        mem.Seek(0,soFromBeginning);
+        mem.Read(target^,mem.size);
+        mem.Free;
+      end;
+      FQuery.Close;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateRawFile(fileid,dat_offset:LongWord; size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE rawmap SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+procedure TOniDataADB.LoadRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    data:Tdata;
+    mem:TMemoryStream;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      SetLength(data, Self.GetRawInfo(fileid,dat_offset).raw_size);
+      Self.LoadRawFile(fileid,dat_offset,@data[0]);
+      mem:=TMemoryStream.Create;
+      mem.Write(data[offset],size);
+      mem.Read(target^,size);
+      mem.Free;
+    end;
+  end;
+
+procedure TOniDataADB.UpdateRawFilePart(fileid,dat_offset:LongWord; offset,size:LongWord; target:Pointer);
+  var
+    MimeCoder: TStringFormat_MIME64;
+    mem:TMemoryStream;
+    data:Tdata;
+  begin
+    if fileid<Self.GetFilesCount then begin
+      SetLength(data, Self.GetRawInfo(fileid,offset).raw_size);
+      Self.LoadRawFile(fileid,offset,@data[0]);
+      mimecoder:=TStringFormat_MIME64.Create;
+      mem:=TMemoryStream.Create;
+      mem.Write(data[0],Length(data));
+      mem.Seek(offset,soFromBeginning);
+      mem.Write(target^,size);
+      mem.Seek(0,soFromBeginning);
+      FQuery.SQL.Text:='UPDATE rawmap SET data=MimeToBin("'+MimeCoder.StrTo(mem.Memory, mem.Size)+'") WHERE (src_id='+IntToStr(fileid)+') AND (src_link_offset='+IntToStr(dat_offset)+');';
+      FQuery.ExecSQL;
+      mem.Free;
+      mimecoder.Free;
+    end;
+  end;
+
+
+
+
+
+
+
+
+
+
+
+function CreateDataConnection(filename:String; backend:Integer):Boolean;
+  var
+    answer:Boolean;
+  begin
+    if Assigned(OniDataConnection) then begin
+      OniDataConnection.Close;
+      OniDataConnection.Free;
+      OniDataConnection:=Nil;
+    end;
+    case backend of
+      ODB_Dat: OniDataConnection:=TOniDataDat.Create(filename, answer);
+      ODB_ADB: OniDataConnection:=TOniDataADB.Create(filename, answer);
+    else
+      ShowMessage('Unknown Backend');
+      Result:=False;
+      Exit;
+    end;
+
+    if answer then begin
+//      ShowMessage('file loaded');
+//      ShowMessage('Files: '+IntToStr(OniDataConnection.GetFilesCount));
+      Result:=True;
+    end else begin
+      ShowMessage('File not loaded');
+      OniDataConnection.Close;
+      OniDataConnection.Free;
+      Result:=False;
+    end;
+  end;
+
+procedure CloseDataConnection;
+  begin
+    if Assigned(OniDataConnection) then begin
+      OniDataConnection.Close;
+      OniDataConnection:=Nil;
+    end;
+  end;
+
+end.
Index: /oup/releases/0.32a/src/Unit1_main.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit1_main.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit1_main.dfm	(revision 8)
@@ -0,0 +1,190 @@
+object Form1: TForm1
+  Left = 0
+  Top = 0
+  HorzScrollBar.Visible = False
+  VertScrollBar.Visible = False
+  Caption = 'Form1'
+  ClientHeight = 495
+  ClientWidth = 577
+  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 = 478
+    Width = 577
+    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 = 458
+    Width = 577
+    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 = 328
+  end
+  object menu: TMainMenu
+    AutoHotkeys = maManual
+    Left = 424
+    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_CloseFileDB: TMenuItem
+        Caption = '&Close file/DB'
+        OnClick = menu_CloseFileDBClick
+      end
+      object menu_sep1: TMenuItem
+        Caption = '-'
+      end
+      object menu_settings: TMenuItem
+        Caption = 'Se&ttings...'
+        OnClick = menu_settingsClick
+      end
+      object menu_sep4: TMenuItem
+        Caption = '-'
+      end
+      object menu_exit: TMenuItem
+        Caption = '&Exit'
+        OnClick = menu_exitClick
+      end
+    end
+    object menu_convert: TMenuItem
+      Caption = '&Convert'
+      object menu_createdb: TMenuItem
+        Caption = 'Create level-database ...'
+        OnClick = menu_createdbClick
+      end
+      object menu_createlvl: TMenuItem
+        Caption = 'Create level-files ...'
+        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_rawedit: TMenuItem
+        Caption = 'Binary .&raw editor ...'
+        ShortCut = 16466
+        OnClick = menu_raweditClick
+      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_filecompare: TMenuItem
+        Caption = '&File compare ...'
+        Enabled = False
+        ShortCut = 16454
+        OnClick = menu_filecompareClick
+      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
+    object menu_About: TMenuItem
+      Caption = '&About'
+      OnClick = menu_AboutClick
+    end
+  end
+  object saved: TSaveDialog
+    Options = [ofOverwritePrompt, ofPathMustExist, ofEnableSizing]
+    Left = 376
+  end
+end
Index: /oup/releases/0.32a/src/Unit1_main.pas
===================================================================
--- /oup/releases/0.32a/src/Unit1_main.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit1_main.pas	(revision 8)
@@ -0,0 +1,530 @@
+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, Unit9_data_structures,
+  Unit10_leveldb, Unit4_exporters, Unit14_settings,
+  Unit5_preview, Unit7_txmpreplace, Unit8_binedit, Unit11_extractor, Unit13_rawedit,
+  Unit15_Classes;
+
+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;
+    menu_rawedit: TMenuItem;
+    menu_filecompare: TMenuItem;
+    menu_CloseFileDB: TMenuItem;
+    menu_sep4: TMenuItem;
+    menu_settings: TMenuItem;
+    menu_About: TMenuItem;
+    FUNCTION TryCloseAll:Boolean;
+    procedure menu_AboutClick(Sender: TObject);
+    PROCEDURE menu_settingsClick(Sender: TObject);
+    PROCEDURE menu_CloseFileDBClick(Sender: TObject);
+    PROCEDURE menu_filecompareClick(Sender: TObject);
+    PROCEDURE menu_raweditClick(Sender: TObject);
+    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);
+    FUNCTION open_child(window_context:String):Boolean;
+    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);
+    PROCEDURE UpdateStatBar;
+  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';
+      AppSettings.FilenumbersAsHex:=False;
+      AppSettings.CharSet:=DEFAULT_CHARSET;
+      AppSettings.HideUnusedData:=False;
+    END;
+
+    IF MidStr(ParamStr(1),1,3)='opf' THEN BEGIN
+      ShowMessage('Load OPF-File: '+ParamStr(2));
+    END ELSE IF MidStr(ParamStr(1),1,4)='oldb' THEN BEGIN
+      IF NOT CreateDataConnection(ParamStr(2), ODB_ADB) THEN
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an OniUnPacker-LevelDatabase-file?');
+    END ELSE IF MidStr(ParamStr(1),1,3)='dat' THEN BEGIN
+      IF NOT CreateDataConnection(ParamStr(2), ODB_Dat) THEN
+        ShowMessage('Error while loading the file:'+CrLf+ParamStr(2)+CrLf+'Perhaps not an Oni-.dat-file?');
+    END;
+    UpdateStatBar;
+  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;
+
+
+PROCEDURE TForm1.UpdateStatBar;
+  BEGIN
+    IF Assigned(OniDataConnection) THEN BEGIN
+      Form1.Caption:='Oni Un/Packer '+version+' ('+ExtractFileName(OniDataConnection.FileName)+')';
+      menu_tools.Enabled:=True;
+      menu_convert.Enabled:=False;
+      statbar.Panels.Items[1].Text:='Files: '+IntToStr(OniDataConnection.GetFilesCount);
+      statbar.Panels.Items[2].Text:='Extensions: '+IntToStr(Length(OniDataConnection.GetExtensionsList));
+      CASE OniDataConnection.Backend OF
+        ODB_Dat:
+          BEGIN
+            statbar.Panels.Items[0].Text:='.dat loaded: '+OniDataConnection.FileName;
+          END;
+        ODB_ADB:
+          BEGIN
+            statbar.Panels.Items[0].Text:='OLDB loaded: '+OniDataConnection.FileName;
+          END;
+      ELSE
+        Form1.Caption:='Oni Un/Packer '+version;
+        statbar.Panels.Items[0].Text:='Nothing loaded';
+        statbar.Panels.Items[1].Text:='Files: -';
+        statbar.Panels.Items[2].Text:='Extensions: -';
+        menu_tools.Enabled:=False;
+        menu_convert.Enabled:=True;
+      END;
+    END ELSE BEGIN
+      Form1.Caption:='Oni Un/Packer '+version;
+      statbar.Panels.Items[0].Text:='Nothing loaded';
+      statbar.Panels.Items[1].Text:='Files: -';
+      statbar.Panels.Items[2].Text:='Extensions: -';
+      menu_tools.Enabled:=False;
+      menu_convert.Enabled:=True;
+    END;
+  END;
+
+
+FUNCTION TForm1.TryCloseAll:Boolean;
+  BEGIN
+    menu_windows_closeallClick(Self);
+    IF Length(tablist)=0 THEN
+      Result:=True
+    ELSE
+      Result:=False;
+  END;
+
+
+{#################################}
+{##### Main-Menu-Handlers    #####}
+{#################################}
+PROCEDURE TForm1.menu_loaddatClick(Sender: TObject);
+  VAR i:LongWord;
+    answer:Boolean;
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      opend.InitialDir:=AppSettings.DatPath;
+      opend.Filter:='Oni-Dat-Files|*.dat';
+      IF opend.Execute THEN BEGIN
+        IF NOT CreateDataConnection(opend.FileName, ODB_Dat) THEN
+          ShowMessage('Error while loading the file:'+CrLf+opend.FileName+CrLf+'Perhaps not an Oni-.dat-file?');
+        AppSettings.DatPath:=ExtractFilepath(opend.FileName);
+      END;
+    END;
+    UpdateStatBar;
+  END;
+PROCEDURE TForm1.menu_lvldbClick(Sender: TObject);
+  VAR answer:Boolean;
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      opend.InitialDir:=AppSettings.DatPath;
+      opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+      IF opend.Execute THEN BEGIN
+        IF NOT CreateDataConnection(opend.FileName, ODB_ADB) THEN
+          ShowMessage('Error while loading the file:'+CrLf+opend.FileName+CrLf+'Perhaps not an OniUnPacker-LevelDatabase-file?');
+        AppSettings.DatPath:=ExtractFilepath(opend.FileName);
+      END;
+    END;
+    UpdateStatBar;
+  END;
+PROCEDURE TForm1.menu_CloseFileDBClick(Sender: TObject);
+  BEGIN
+    IF TryCloseAll THEN BEGIN
+      CloseDataConnection;
+      UpdateStatBar;
+    END;
+  END;
+PROCEDURE TForm1.menu_settingsClick(Sender: TObject);
+  BEGIN
+    Form14.Visible:=True;
+    Self.Enabled:=False;
+  END;
+PROCEDURE TForm1.menu_exitClick(Sender: TObject);
+  BEGIN
+    Form1.Close;
+  END;
+
+{####################################}
+{##### Converters-Menu-Handlers #####}
+{####################################}
+PROCEDURE TForm1.menu_createdbClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='Oni-Dat-Files|*.dat';
+    saved.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.DefaultExt:='oldb';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateDatabase(opend.FileName,saved.FileName);
+      END;
+    END;
+  END;
+PROCEDURE TForm1.menu_createlvlClick(Sender: TObject);
+  BEGIN
+    opend.Filter:='OUP-Level-DB (*.oldb)|*.oldb';
+    saved.Filter:='Oni-Dat-Files|*.dat';
+    saved.DefaultExt:='dat';
+    IF opend.Execute THEN BEGIN
+      IF saved.Execute THEN BEGIN
+        Form10.CreateLevel(opend.FileName,saved.FileName);
+      END;
+    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_raweditClick(Sender: TObject);
+  BEGIN
+    open_child('rawedit');
+  END;
+
+PROCEDURE TForm1.menu_extractorClick(Sender: TObject);
+  BEGIN
+    open_child('extractor');
+  END;
+PROCEDURE TForm1.menu_filecompareClick(Sender: TObject);
+  BEGIN
+    open_child('compare');
+  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.menu_AboutClick(Sender: TObject);
+  begin
+    ShowMessage('Will be implemented later ;)');
+  end;
+
+
+
+
+FUNCTION TForm1.open_child(window_context:String):Boolean;
+  VAR
+    rawEdit:TForm13;
+    binEdit:TForm8;
+    preview:TForm5;
+    txmpreplacer:TForm7;
+    extractor:TForm11;
+    menu_button:TMenuItem;
+    used:Array[1..9] OF Boolean;
+    i:Byte;
+    caption:String;
+    name:String;
+  BEGIN
+    Result:=True;
+    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='rawedit' THEN
+        caption:='Binary .raw-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='rawedit' THEN BEGIN
+        rawEdit:=TForm13.Create(Application);
+        rawEdit.Name:=name;
+        rawEdit.Caption:=caption;
+        rawEdit.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 ELSE BEGIN
+      Result:=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.32a/src/Unit2_functions.pas
===================================================================
--- /oup/releases/0.32a/src/Unit2_functions.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit2_functions.pas	(revision 8)
@@ -0,0 +1,294 @@
+UNIT Unit2_functions;
+INTERFACE
+USES Classes, Dialogs, SysUtils, StrUtils, Math,
+      Unit3_data;
+
+TYPE
+  TExportSet=SET OF (DO_dat,DO_raw,DO_convert,DO_toone);
+
+FUNCTION BoolToStr(bool:Boolean):String;
+FUNCTION HexToLong(hex:String):LongWord;
+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 ExportFile(fileid:LongWord; filename:String; settings:TExportSet; path:String):Integer;
+
+FUNCTION StringSmaller(string1,string2:String):Boolean;
+
+FUNCTION FormatNumber(value:LongWord; width:Byte; leadingzeros:Char):String;
+FUNCTION FormatFileSize(size:LongWord):String;
+FUNCTION CreateHexString(data:Tdata; HexOnly:Boolean):String;
+FUNCTION DecodeHexString(hex:String):Tdata;
+FUNCTION GetWinFileName(name:String):String;
+FUNCTION GetExtractPath:String;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringArray;
+
+
+IMPLEMENTATION
+USES Unit4_Exporters, Unit15_Classes;
+
+TYPE
+  TValueSwitcher=Record
+    CASE IsFloat: Boolean OF
+      True: (ValueFloat:Single);
+      False: (ValueInt:LongWord);
+  END;
+
+FUNCTION BoolToStr(bool:Boolean):String;
+  BEGIN
+    IF bool THEN
+      Result:='true'
+    ELSE
+      Result:='false';
+  END;
+
+FUNCTION HexToLong(hex:String):LongWord;
+  FUNCTION NormalizeHexString(VAR hex:String):Boolean;
+    VAR
+      i:Byte;
+    BEGIN
+      IF hex[1]='$' THEN BEGIN
+        FOR i:=1 TO Length(hex)-1 DO BEGIN
+          hex[i]:=hex[i+1];
+        END;
+        SetLength(hex, Length(hex)-1);
+      END;
+      IF (hex[1]='0') AND (UpCase(hex[2])='X') THEN BEGIN
+        FOR i:=1 TO Length(hex)-2 DO BEGIN
+          hex[i]:=hex[i+2];
+        END;
+        SetLength(hex, Length(hex)-2);
+      END;
+      IF Length(hex)=0 THEN
+        Result:=False
+      ELSE
+        Result:=True;
+    END;
+  VAR
+    i:Byte;
+  BEGIN
+    IF NormalizeHexString(hex) THEN BEGIN
+      hex:=UpperCase(hex);
+      Result:=0;
+      FOR i:=1 TO Length(hex) DO BEGIN
+        Result:=Result SHL 4;
+        CASE hex[i] OF
+          '0'..'9': Result:=Result+Ord(hex[i])-48;
+          'A'..'F': Result:=Result+Ord(hex[i])-55;
+        ELSE
+          Result:=0;
+          Exit;
+        END;
+      END;
+    END ELSE BEGIN
+      Result:=0;
+    END;
+  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;
+    IF IsNAN(Result) THEN Result:=0.0;
+  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 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 DecodeHexString(hex:String):Tdata;
+  VAR
+    i:LongWord;
+  BEGIN
+    SetLength(Result, Length(hex) DIV 2);
+    FOR i:=0 TO Length(Result) DO BEGIN
+      Result[i]:=0;
+      CASE UpCase(hex[1+i*2]) OF
+        '0'..'9': Result[i]:=(Ord(UpCase(hex[1+i*2]))-48)*16;
+        'A'..'F': Result[i]:=(Ord(UpCase(hex[1+i*2]))-55)*16;
+      END;
+      CASE UpCase(hex[1+i*2+1]) OF
+        '0'..'9': Result[i]:=Result[i]+(Ord(UpCase(hex[1+i*2+1]))-48);
+        'A'..'F': Result[i]:=Result[i]+(Ord(UpCase(hex[1+i*2+1]))-55);
+      END;
+    END;
+  END;
+
+
+
+FUNCTION StringSmaller(string1,string2:String):Boolean;
+  VAR
+    i:Integer;
+    len:Integer;
+  BEGIN
+    len:=Min(Length(string1),Length(string2));
+    FOR i:=1 TO len DO
+      IF Ord(string1[i])<>Ord(string2[i]) THEN BEGIN
+        Result:=Ord(string1[i])<Ord(string2[i]);
+        Exit;
+      END;
+    Result:=Length(string1)<Length(string2);
+  END;
+
+
+
+
+FUNCTION ExportFile(fileid:LongWord; filename:String; settings:TExportSet; path:String):Integer;
+  VAR
+    i:Byte;
+    extension:String;
+    rawlist:TRawList;
+  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
+        rawlist:=OniDataConnection.GetRawList(fileid);
+        IF Length(rawlist)>0 THEN BEGIN
+          FOR i:=0 TO High(rawlist) DO BEGIN
+            ExportRawFile(fileid,rawlist[i].src_offset,path+'\'+GetWinFileName(filename));
+          END;
+        END;
+      END;
+    END;
+  END;
+
+FUNCTION Explode(_string:String; delimiter:Char):TStringArray;
+  VAR
+    start,len:Word;
+  BEGIN
+    SetLength(Result, 0);
+    start:=1;
+    WHILE PosEx(delimiter,_string,start)>0 DO BEGIN
+      len:=PosEx(delimiter,_string,start)-start;
+      SetLength(Result, Length(Result)+1);
+      Result[High(Result)]:=MidStr(_string,start,len);
+      start:=start+len+1;
+    END;
+    SetLength(Result, Length(Result)+1);
+    Result[High(Result)]:=MidStr(_string,start,Length(_string)-start+1);
+  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(OniDataConnection.FileName)+'\extracted_'+ExtractFileName(OniDataConnection.Filename);
+  END;
+
+
+END.
Index: /oup/releases/0.32a/src/Unit3_data.pas
===================================================================
--- /oup/releases/0.32a/src/Unit3_data.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit3_data.pas	(revision 8)
@@ -0,0 +1,130 @@
+unit Unit3_data;
+interface
+uses Classes, Graphics;
+
+const
+  Version:String='v0.32a';
+  DBVersion:String='0.3';
+  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:Integer;
+    FileName:String;
+    FileNameHex: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;
+
+  TLevelInfo=Record
+    Ident:Array[0..$13] of Byte;
+    LevelNumber:Byte;
+  end;
+
+  TAppSettings=Record
+    DatPath:String[250];
+    ExtractPath:String[250];
+    FilenumbersAsHex:Boolean;
+    CharSet:TFontCharSet;
+    HideUnusedData:Boolean;
+  end;
+
+  TExportHandlers=Record
+    Ext:String[4];
+    needed:Boolean;
+    Handler:Function(fileid:LongWord; filename:String; convert:Boolean):Integer;
+  end;
+
+  TStringArray=Array of String;
+  TExtList=Array of Record
+    Ext:String;
+    count:LongWord;
+  end;
+
+  TRawInfo=Record
+    src_id:LongWord;
+    src_offset:LongWord;
+    raw_addr:LongWord;
+    raw_size:LongWord;
+    loc_sep:Boolean;
+  end;
+  TRawList=Array of TRawInfo;
+
+  TDatLinks=Array of Record
+    Src_Offset:LongWord;
+    Target:LongWord;
+  END;
+
+var
+{
+  opened_state:Byte=0;
+  dat_filename:String='';
+  raw_filename:String='';
+  dat_os_mac:Boolean=False;
+  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_pc: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_ident1_mac:Array[0..$13] of Byte=
+      ($61,$30,$C1,$23,$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.32a/src/Unit4_Exporters.pas
===================================================================
--- /oup/releases/0.32a/src/Unit4_Exporters.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit4_Exporters.pas	(revision 8)
@@ -0,0 +1,218 @@
+UNIT Unit4_Exporters;
+INTERFACE
+USES Classes, Dialogs, StrUtils, SysUtils, Math, Unit3_data, Unit6_imgfuncs;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset: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, Unit9_data_structures, Unit15_Classes;
+
+PROCEDURE ExportDatFile(fileid:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    data:=OniDataConnection.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;
+
+PROCEDURE ExportRawFile(fileid:LongWord; dat_offset:LongWord; filename:String);
+  VAR
+    filestream:TFileStream;
+    data:Tdata;
+  BEGIN
+    SetLength(data, OniDataConnection.GetRawInfo(fileid, dat_offset).raw_size);
+    OniDataConnection.LoadRawFile(fileid,dat_offset,@data[0]);
+    IF FileExists(filename+'.raw0x'+IntToHex(dat_offset,8)) THEN BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),fmOpenReadWrite);
+      filestream.Seek(0,soFromEnd);
+    END ELSE BEGIN
+      filestream:=TFileStream.Create(filename+'.raw0x'+IntToHex(dat_offset,8),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;
+    OniDataConnection.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);
+        OniDataConnection.LoadRawFile(fileid,$44,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;
+
+    OniDataConnection.LoadDatFilePart(fileid,$18,SizeOf(link),@link);
+    link:=link DIV 256;
+
+    OniDataConnection.LoadDatFilePart(fileid,$1E,SizeOf(linkcount),@linkcount);
+    FOR i:=1 TO linkcount DO BEGIN
+      OniDataConnection.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;
+
+    OniDataConnection.LoadDatFilePart(fileid,$14,SizeOf(loop_speed),@loop_speed);
+    OniDataConnection.LoadDatFilePart(fileid,$16,SizeOf(unknown),@unknown);
+
+    OniDataConnection.LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      OniDataConnection.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.32a/src/Unit5_preview.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit5_preview.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit5_preview.dfm	(revision 8)
@@ -0,0 +1,192 @@
+object Form5: TForm5
+  Left = 0
+  Top = 0
+  Caption = 'Preview'
+  ClientHeight = 473
+  ClientWidth = 472
+  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.32a/src/Unit5_preview.pas
===================================================================
--- /oup/releases/0.32a/src/Unit5_preview.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit5_preview.pas	(revision 8)
@@ -0,0 +1,287 @@
+UNIT Unit5_preview;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, Math, ExtCtrls, StdCtrls, StrUtils, Menus,
+  Unit2_functions, Unit3_data, Unit4_exporters, Unit6_imgfuncs, Unit15_Classes;
+
+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
+    memstreams:Array OF TMemoryStream;
+    actualimg:Byte;
+    _fileid:LongWord;
+  PUBLIC
+  END;
+
+VAR
+  Form5: TForm5;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main;
+
+
+PROCEDURE TForm5.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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:=OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]);
+    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
+    OniImage:TOniImage;
+    data:Tdata;
+  BEGIN
+    SetLength(memstreams,1);
+    OniImage:=TOniImage.Create;
+    OniImage.LoadFromTXMB(_fileid);
+    data:=OniImage.GetAsBMP;
+    OniImage.Free;
+
+    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
+    OniImage:TOniImage;
+    data:Tdata;
+  BEGIN
+    SetLength(memstreams,1);
+    OniImage:=TOniImage.Create;
+    OniImage.LoadFromTXMP(_fileid);
+    data:=OniImage.GetAsBMP;
+    OniImage.Free;
+
+    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;
+    OniImage:TOniImage;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(_fileid,$14,SizeOf(loop_speed),@loop_speed);
+    OniDataConnection.LoadDatFilePart(_fileid,$1C,SizeOf(linkcount),@linkcount);
+    SetLength(memstreams,linkcount);
+    FOR i:=0 TO linkcount-1 DO BEGIN
+      OniDataConnection.LoadDatFilePart(_fileid,$20+i*4,SizeOf(link),@link);
+      link:=link DIV 256;
+      IF link=0 THEN link:=_fileid-1;
+      memstreams[i]:=TMemoryStream.Create;
+      OniImage:=TOniImage.Create;
+      OniImage.LoadFromTXMP(link);
+      data:=OniImage.GetAsBMP;
+      OniImage.Free;
+      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 '+OniDataConnection.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 '+OniDataConnection.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 '+OniDataConnection.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.32a/src/Unit6_imgfuncs.pas
===================================================================
--- /oup/releases/0.32a/src/Unit6_imgfuncs.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit6_imgfuncs.pas	(revision 8)
@@ -0,0 +1,593 @@
+unit Unit6_imgfuncs;
+interface
+uses Math, Dialogs, SysUtils, Classes, Unit3_data, Unit15_Classes;
+
+{
+type
+  TImgPackage=record
+    imgx,imgy:Word;
+    imgdepth:Byte;
+    storetype:Byte;
+    datasize:LongWord;
+    raw_addr:LongWord;
+    imgdata:Tdata;
+  end;
+}
+type
+  TImgDataType=Set of (DT_OniReverted,DT_Oni,DT_MipMapped,DT_Decoded32);
+
+type
+  TOniImage = class
+    private
+      FLoaded:Boolean;
+      FDataType:TImgDataType;
+      FData:Tdata;
+      FWidth,FHeight:Word;
+      FDepth:Byte;
+      FStoreType:Byte;
+
+      function ResizeImage(oldx,oldy:LongWord; img:Tdata):Tdata;
+      procedure RevertImage;
+      procedure DecodeImage;
+      procedure DecompressImage;
+    protected
+    public
+      property Loaded:Boolean read FLoaded;
+      property DataType:TImgDataType read FDataType;
+      property Width:Word read FWidth;
+      property Height:Word read FHeight;
+      property Depth:Byte read FDepth;
+      property StoreType:Byte read FStoreType;
+      property Data:Tdata read FData;
+
+      constructor Create;
+      function LoadFromTXMP(fileid:LongWord):Boolean;
+      function LoadFromTXMB(fileid:LongWord):Boolean;
+      function GetImageDataSize(fading:Boolean):LongWord;
+
+      function GetAsData:Tdata;
+      function GetAs32bit:Tdata;
+      function GetAsBMP:Tdata;
+      function LoadFromBMP(filename:String):Boolean;
+      function WriteToBMP(filename:String):Boolean;
+      function GetMipMappedImage(var faded:Tdata):Boolean;
+    published
+  end;
+
+
+implementation
+uses Unit2_functions;
+
+
+
+constructor TOniImage.Create;
+  begin
+    Self.FLoaded:=False;
+    Self.FDataType:=[];
+    SetLength(Self.FData,0);
+    Self.FWidth:=0;
+    Self.FHeight:=0;
+    Self.FDepth:=0;
+    Self.FStoreType:=0;
+  end;
+
+
+
+function TOniImage.ResizeImage(oldx,oldy:LongWord; img:Tdata):Tdata;
+  var
+    i,j:LongWord;
+    col,row,row_orig:LongWord;
+  begin
+    SetLength(Result,(oldx div 2)*(oldy div 2)*(Self.FDepth 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 (Self.FDepth div 8)-1 do
+            Result[((row*(oldx div 2))+col)*(Self.FDepth div 8)+j]:=img[(i*(Self.FDepth div 8))+j];
+          Inc(col);
+        end;
+      end;
+    end;
+  end;
+
+
+
+procedure TOniImage.RevertImage;
+  var
+    x,y,i:LongWord;
+    tempd:Tdata;
+  begin
+    SetLength(tempd, Self.FWidth * Self.FHeight *(Self.FDepth div 8));
+    for y:=0 to Self.FHeight-1 do
+      for x:=0 to Self.FWidth-1 do
+        for i:=0 to (Self.FDepth div 8)-1 do
+          tempd[((Self.FWidth*(Self.FHeight-1-y)+x)*(Self.FDepth div 8))+i]:=
+                  Self.FData[(Self.FWidth*y+x)*(Self.FDepth div 8)+i];
+    for x:=0 to High(tempd) do
+      Self.FData[x]:=tempd[x];
+    if DT_OniReverted in Self.FDataType then
+      Self.FDataType:=Self.FDataType-[DT_OniReverted]
+    else
+      Self.FDataType:=Self.FDataType+[DT_OniReverted];
+    if DT_MipMapped in Self.FDataType then
+      Self.FDataType:=Self.FDataType-[DT_MipMapped];
+  end;
+
+
+
+procedure TOniImage.DecodeImage;
+  var
+    x,y:LongWord;
+    tempd:Tdata;
+  begin
+    if not (DT_Decoded32 in Self.FDataType) then begin
+      SetLength(tempd, Self.FWidth * Self.FHeight * 4);
+      case Self.FStoreType of
+        0: begin
+            for y:=0 to Self.FHeight-1 do begin
+              for x:=0 to Self.FWidth-1 do begin
+                tempd[((Self.FWidth*y+x)*4)+0]:=Floor( ( (Self.FData[(Self.FWidth*y+x)*2]+Self.FData[(Self.FWidth*y+x)*2+1]*256) AND $000F ) / $000F * 255);
+                tempd[((Self.FWidth*y+x)*4)+1]:=Floor( ( (Self.FData[(Self.FWidth*y+x)*2]+Self.FData[(Self.FWidth*y+x)*2+1]*256) AND $00F0 ) / $00F0 * 255);
+                tempd[((Self.FWidth*y+x)*4)+2]:=Floor( ( (Self.FData[(Self.FWidth*y+x)*2]+Self.FData[(Self.FWidth*y+x)*2+1]*256) AND $0F00 ) / $0F00 * 255);
+                tempd[((Self.FWidth*y+x)*4)+3]:=0;
+              end;
+            end;
+          end;
+        1,2: begin
+            for y:=0 to Self.FHeight-1 do begin
+              for x:=0 to Self.FWidth-1 do begin
+                tempd[((Self.FWidth*y+x)*4)+0]:=Floor( ( (Self.FData[(Self.FWidth*y+x)*2]+Self.FData[(Self.FWidth*y+x)*2+1]*256) AND $001F ) / $001F * 255);
+                tempd[((Self.FWidth*y+x)*4)+1]:=Floor( ( (Self.FData[(Self.FWidth*y+x)*2]+Self.FData[(Self.FWidth*y+x)*2+1]*256) AND $03E0 ) / $03E0 * 255);
+                tempd[((Self.FWidth*y+x)*4)+2]:=Floor( ( (Self.FData[(Self.FWidth*y+x)*2]+Self.FData[(Self.FWidth*y+x)*2+1]*256) AND $7C00 ) / $7C00 * 255);
+                tempd[((Self.FWidth*y+x)*4)+3]:=0;
+              end;
+            end;
+          end;
+        9: begin
+            DecompressImage;
+          end;
+      end;
+      Self.FDepth:=32;
+      if (Self.FStoreType<>9) AND (Self.FStoreType<>8) then begin
+        SetLength(Self.FData, Length(tempd));
+        for x:=0 to High(tempd) do
+          Self.FData[x]:=tempd[x];
+      end;
+      Self.FStoreType:=8;
+      if DT_Oni in Self.FDataType then
+        Self.FDataType:=Self.FDataType-[DT_Oni];
+      Self.FDataType:=Self.FDataType+[DT_Decoded32];
+    end;
+    if DT_MipMapped in Self.FDataType then
+      Self.FDataType:=Self.FDataType-[DT_MipMapped];
+    if DT_OniReverted in Self.FDataType then
+      Self.RevertImage;
+  end;
+
+
+
+procedure TOniImage.DecompressImage;
+  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;
+    tempd:Tdata;
+  begin
+    x:=0;
+    y:=0;
+    SetLength(tempd, Self.FWidth * Self.FHeight * 4);
+    for i:=0 to ((Self.FWidth * Self.FHeight) div 16)-1 do begin
+      Color[1].RGBb:=Floor(((Self.FData[(i*8)+0]+Self.FData[(i*8)+1]*256) and $001F) / $001F * 255);
+      Color[1].RGBg:=Floor(((Self.FData[(i*8)+0]+Self.FData[(i*8)+1]*256) and $07E0) / $07E0 * 255);
+      Color[1].RGBr:=Floor(((Self.FData[(i*8)+0]+Self.FData[(i*8)+1]*256) and $F800) / $F800 * 255);
+      Color[1].RGBa:=255;
+      Color[2].RGBb:=Floor(((Self.FData[(i*8)+2]+Self.FData[(i*8)+3]*256) and $001F) / $001F * 255);
+      Color[2].RGBg:=Floor(((Self.FData[(i*8)+2]+Self.FData[(i*8)+3]*256) and $07E0) / $07E0 * 255);
+      Color[2].RGBr:=Floor(((Self.FData[(i*8)+2]+Self.FData[(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( (Self.FData[(i*8)+4] and $C0) / $40 + 1 );
+      Pixel[2]:=Floor( (Self.FData[(i*8)+4] and $30) / $10 + 1 );
+      Pixel[3]:=Floor( (Self.FData[(i*8)+4] and $0C) / $04 + 1 );
+      Pixel[4]:=Floor( (Self.FData[(i*8)+4] and $03) + 1 );
+      Pixel[5]:=Floor( (Self.FData[(i*8)+5] and $C0) / $40 + 1 );
+      Pixel[6]:=Floor( (Self.FData[(i*8)+5] and $30) / $10 + 1 );
+      Pixel[7]:=Floor( (Self.FData[(i*8)+5] and $0C) / $04 + 1 );
+      Pixel[8]:=Floor( (Self.FData[(i*8)+5] and $03) + 1 );
+      Pixel[9]:=Floor( (Self.FData[(i*8)+6] and $C0) / $40 + 1 );
+      Pixel[10]:=Floor( (Self.FData[(i*8)+6] and $30) / $10 + 1 );
+      Pixel[11]:=Floor( (Self.FData[(i*8)+6] and $0C) / $04 + 1 );
+      Pixel[12]:=Floor( (Self.FData[(i*8)+6] and $03) + 1 );
+      Pixel[13]:=Floor( (Self.FData[(i*8)+7] and $C0) / $40 + 1 );
+      Pixel[14]:=Floor( (Self.FData[(i*8)+7] and $30) / $10 + 1 );
+      Pixel[15]:=Floor( (Self.FData[(i*8)+7] and $0C) / $04 + 1 );
+      Pixel[16]:=Floor( (Self.FData[(i*8)+7] and $03) + 1 );
+      for j:=0 to 3 do begin
+        tempd[((y+3)*Self.FWidth+x+j)*4+0]:=Color[Pixel[16-j]].RGBb;
+        tempd[((y+3)*Self.FWidth+x+j)*4+1]:=Color[Pixel[16-j]].RGBg;
+        tempd[((y+3)*Self.FWidth+x+j)*4+2]:=Color[Pixel[16-j]].RGBr;
+        tempd[((y+3)*Self.FWidth+x+j)*4+3]:=0;
+      end;
+      for j:=0 to 3 do begin
+        tempd[((y+2)*Self.FWidth+x+j)*4+0]:=Color[Pixel[12-j]].RGBb;
+        tempd[((y+2)*Self.FWidth+x+j)*4+1]:=Color[Pixel[12-j]].RGBg;
+        tempd[((y+2)*Self.FWidth+x+j)*4+2]:=Color[Pixel[12-j]].RGBr;
+        tempd[((y+2)*Self.FWidth+x+j)*4+3]:=0;
+      end;
+      for j:=0 to 3 do begin
+        tempd[((y+1)*Self.FWidth+x+j)*4+0]:=Color[Pixel[8-j]].RGBb;
+        tempd[((y+1)*Self.FWidth+x+j)*4+1]:=Color[Pixel[8-j]].RGBg;
+        tempd[((y+1)*Self.FWidth+x+j)*4+2]:=Color[Pixel[8-j]].RGBr;
+        tempd[((y+1)*Self.FWidth+x+j)*4+3]:=0;
+      end;
+      for j:=0 to 3 do begin
+        tempd[((y+0)*Self.FWidth+x+j)*4+0]:=Color[Pixel[4-j]].RGBb;
+        tempd[((y+0)*Self.FWidth+x+j)*4+1]:=Color[Pixel[4-j]].RGBg;
+        tempd[((y+0)*Self.FWidth+x+j)*4+2]:=Color[Pixel[4-j]].RGBr;
+        tempd[((y+0)*Self.FWidth+x+j)*4+3]:=0;
+      end;
+      x:=x+4;
+      if x=Self.FWidth THEN begin
+        y:=y+4;
+        x:=0;
+      end;
+    end;
+    SetLength(Self.FData, Length(tempd));
+    for i:=0 to High(tempd) do
+      Self.FData[i]:=tempd[i];
+    if DT_MipMapped in Self.FDataType then
+      Self.FDataType:=Self.FDataType-[DT_MipMapped];
+  end;
+
+
+
+
+
+function TOniImage.LoadFromTXMP(fileid:LongWord):Boolean;
+  var
+    img_addr:LongWord;
+  begin
+    Result:=True;
+    OniDataConnection.LoadDatFilePart(fileid,$8C,SizeOf(Self.FWidth),@Self.FWidth);
+    OniDataConnection.LoadDatFilePart(fileid,$8E,SizeOf(Self.FHeight),@Self.FHeight);
+    OniDataConnection.LoadDatFilePart(fileid,$90,SizeOf(Self.FStoreType),@Self.FStoreType);
+    if not OniDataConnection.OSisMac then
+      OniDataConnection.LoadDatFilePart(fileid,$9C,SizeOf(img_addr),@img_addr)
+    else
+      OniDataConnection.LoadDatFilePart(fileid,$A0,SizeOf(img_addr),@img_addr);
+
+    case Self.FStoreType of
+      0,1,2: begin
+          SetLength(Self.FData, Self.FWidth * Self.FHeight * 2);
+          Self.FDepth:=16;
+        end;
+      8: begin
+          SetLength(Self.FData, Self.FWidth * Self.FHeight * 4);
+          Self.FDepth:=32;
+        end;
+      9: begin
+          SetLength(Self.FData, Self.FWidth * Self.FHeight div 2);
+          Self.FDepth:=16;
+        end;
+    else
+      Result:=False;
+      Exit;
+    end;
+
+    if not OniDataConnection.OSisMac then
+      OniDataConnection.LoadRawFile(fileid,$9C,@Self.FData[0])
+    else
+      OniDataConnection.LoadRawFile(fileid,$A0,@Self.FData[0]);
+
+    Self.FDataType:=[DT_OniReverted,DT_Oni];
+  end;
+
+
+
+function TOniImage.LoadFromTXMB(fileid:LongWord):Boolean;
+  type
+    TImg=record
+      imgx,imgy:Word;
+      imgdepth:Byte;
+      storetype:Byte;
+      datasize:LongWord;
+      raw_addr:LongWord;
+      imgdata:Tdata;
+    end;
+  var
+    i,x,y,x2,y2,pixelid,imgid:LongWord;
+    rows,cols:Word;
+    linkcount:LongWord;
+    link:LongWord;
+    images_decoded:Array of TOniImage;
+    x_start,y_start:LongWord;
+  begin
+    OniDataConnection.LoadDatFilePart(fileid,$10,SizeOf(Self.FWidth),@Self.FWidth);
+    OniDataConnection.LoadDatFilePart(fileid,$12,SizeOf(Self.FHeight),@Self.FHeight);
+    OniDataConnection.LoadDatFilePart(fileid,$18,SizeOf(cols),@cols);
+    OniDataConnection.LoadDatFilePart(fileid,$1A,SizeOf(rows),@rows);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,SizeOf(linkcount),@linkcount);
+    SetLength(images_decoded,linkcount);
+    for i:=0 to linkcount-1 do begin
+      OniDataConnection.LoadDatFilePart(fileid,$20+i*4,SizeOf(link),@link);
+      link:=link div 256;
+      images_decoded[i]:=TOniImage.Create;
+      images_decoded[i].LoadFromTXMP(link);
+      images_decoded[i].DecodeImage;
+      images_decoded[i].RevertImage;
+    end;
+    SetLength(Self.FData, Self.FWidth * Self.FHeight * 4);
+    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].Width;
+        for i:=0 to y do   if i<y then y_start:=y_start+images_decoded[i].Height;
+        for y2:=0 to images_decoded[imgid].Height-1 do begin
+          for x2:=0 to images_decoded[imgid].Width-1 do begin
+            if ( (x_start+x2)<Self.FWidth ) and ( (y_start+y2)<Self.FHeight ) then begin
+              pixelid:=y_start*Self.FWidth+x_start+y2*Self.FWidth+x2;
+              Self.FData[pixelid*4+0]:=images_decoded[imgid].Data[(y2*images_decoded[imgid].Width+x2)*4+0];
+              Self.FData[pixelid*4+1]:=images_decoded[imgid].Data[(y2*images_decoded[imgid].Width+x2)*4+1];
+              Self.FData[pixelid*4+2]:=images_decoded[imgid].Data[(y2*images_decoded[imgid].Width+x2)*4+2];
+              Self.FData[pixelid*4+3]:=images_decoded[imgid].Data[(y2*images_decoded[imgid].Width+x2)*4+3];
+            end;
+          end;
+        end;
+      end;
+    end;
+    for i:=0 to linkcount-1 do
+      images_decoded[i].Free;
+    Self.FDepth:=32;
+    Self.FStoreType:=1;
+    Self.FDataType:=[DT_Decoded32];
+    Self.RevertImage;
+  end;
+
+
+
+function TOniImage.GetImageDataSize(fading:Boolean):LongWord;
+  var
+    size:LongWord;
+    x,y:Word;
+    bpp:Byte;
+  begin
+    case Self.FStoreType of
+        9: bpp:=8;
+        0,1,2: bpp:=16;
+        8: bpp:=32;
+    else
+      Result:=0;
+      Exit;
+    end;
+
+    x:=Self.FWidth;
+    y:=Self.FHeight;
+    size:=x*y*bpp div 8;
+    if fading then begin
+      repeat
+        x:=x div 2;
+        y:=y div 2;
+        size:=size+x*y*bpp div 8;
+      until (x=1) or (y=1);
+    end;
+    Result:=size;
+  end;
+
+
+
+function TOniImage.GetAsData:Tdata;
+  var
+    i: Integer;
+    revert:Boolean;
+  begin
+//    if not (DT_Decoded32 in Self.FDataType) then
+//      Self.DecodeImage;
+    if not (DT_OniReverted in Self.FDataType) then begin
+      revert:=True;
+      Self.RevertImage;
+    end else revert:=False;
+    SetLength(Result, Length(Self.FData));
+    for i:=0 to High(Result) do
+      Result[i]:=Self.FData[i];
+    if revert then
+      Self.RevertImage;
+  end;
+
+
+
+function TOniImage.GetAs32bit:Tdata;
+  var
+    i:Integer;
+  begin
+    if not (DT_Decoded32 in Self.FDataType) then
+      Self.DecodeImage;
+    SetLength(Result,Length(Self.FData));
+    for i:=0 to High(Result) do
+      Result[i]:=Self.FData[i];
+  end;
+
+
+
+function TOniImage.GetAsBMP: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
+    if not (DT_Decoded32 in Self.FDataType) then
+      Self.DecodeImage;
+
+    SetLength(Result, Self.FWidth * Self.FHeight * 3);
+    for y:=0 to Self.FHeight-1 do begin
+      for x:=0 to Self.FWidth-1 do begin
+        Result[((Self.FWidth*y+x)*3)+0]:=Self.FData[(Self.FWidth*y+x)*4+0];
+        Result[((Self.FWidth*y+x)*3)+1]:=Self.FData[(Self.FWidth*y+x)*4+1];
+        Result[((Self.FWidth*y+x)*3)+2]:=Self.FData[(Self.FWidth*y+x)*4+2];
+      end;
+    end;
+
+    SetLength(Result, Self.FWidth * Self.FHeight * 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]:=((Self.FWidth*Self.FHeight*3+54) and $000000FF) div $1;
+    Result[3]:=((Self.FWidth*Self.FHeight*3+54) and $0000FF00) div $100;
+    Result[4]:=((Self.FWidth*Self.FHeight*3+54) and $00FF0000) div $10000;
+    Result[5]:=((Self.FWidth*Self.FHeight*3+54) and $FF000000) div $1000000;
+    Result[18]:=(Self.FWidth and $000000FF) div $1;
+    Result[19]:=(Self.FWidth and $0000FF00) div $100;
+    Result[20]:=(Self.FWidth and $00FF0000) div $10000;
+    Result[21]:=(Self.FWidth and $FF000000) div $1000000;
+    Result[22]:=(Self.FHeight and $000000FF) div $1;
+    Result[23]:=(Self.FHeight and $0000FF00) div $100;
+    Result[24]:=(Self.FHeight and $00FF0000) div $10000;
+    Result[25]:=(Self.FHeight and $FF000000) div $1000000;
+    Result[34]:=((Self.FWidth*Self.FHeight*3) and $000000FF) div $1;
+    Result[35]:=((Self.FWidth*Self.FHeight*3) and $0000FF00) div $100;
+    Result[36]:=((Self.FWidth*Self.FHeight*3) and $00FF0000) div $10000;
+    Result[37]:=((Self.FWidth*Self.FHeight*3) and $FF000000) div $1000000;
+  end;
+
+
+
+function TOniImage.LoadFromBMP(filename:String):Boolean;
+  var
+    filestream:TFileStream;
+    tempd:Tdata;
+
+    x,y:LongWord;
+  begin
+    filestream:=TFileStream.Create(filename, fmOpenRead);
+    SetLength(tempd,filestream.Size);
+    filestream.Read(tempd[0],filestream.Size);
+    filestream.Free;
+
+    if not((tempd[00]=$42) and (tempd[01]=$4D)) then begin
+      Result:=False;
+      ShowMessage('Not a standard 24bit bitmap');
+      Exit;
+    end;
+    if not(tempd[10]=54) then begin
+      Result:=False;
+      ShowMessage('Imagedata has to start at 0x54');
+      Exit;
+    end;
+    if not(tempd[14]=40) then begin
+      Result:=False;
+      ShowMessage('Second bitmap header has to have 40 bytes');
+      Exit;
+    end;
+    if not(tempd[28]=24) then begin
+      Result:=False;
+      ShowMessage('Bitmap has to have 24bits');
+      Exit;
+    end;
+    if not(tempd[30]=0) then begin
+      Result:=False;
+      ShowMessage('Bitmap has to be uncompressed');
+      Exit;
+    end;
+
+    Self.FWidth :=tempd[18]+tempd[19]*256+tempd[20]*256*256+tempd[21]*256*256*256;
+    Self.FHeight:=tempd[22]+tempd[23]*256+tempd[24]*256*256+tempd[25]*256*256*256;
+    Self.FDepth:=32;
+    Self.FStoreType:=8;
+
+    SetLength(Self.FData, Self.FWidth * Self.FHeight * Self.FDepth div 8);
+    for y:=0 to Self.FHeight-1 do begin
+      for x:=0 to Self.FWidth-1 do begin
+        Self.FData[((Self.FWidth*y+x)*4)+0]:=tempd[54+(Self.FWidth*y+x)*3+0];
+        Self.FData[((Self.FWidth*y+x)*4)+1]:=tempd[54+(Self.FWidth*y+x)*3+1];
+        Self.FData[((Self.FWidth*y+x)*4)+2]:=tempd[54+(Self.FWidth*y+x)*3+2];
+        Self.FData[((Self.FWidth*y+x)*4)+3]:=0;
+      end;
+    end;
+
+    Self.FDataType:=[DT_Decoded32];
+  end;
+
+
+
+function TOniImage.WriteToBMP(filename:String):Boolean;
+  var
+    filestream:TFileStream;
+    tempd:Tdata;
+  begin
+    tempd:=Self.GetAsBMP;
+    filestream:=TFileStream.Create(filename,fmCreate);
+    filestream.Write(tempd[0],Length(tempd));
+    filestream.Free;
+  end;
+
+
+
+function TOniImage.GetMipMappedImage(var faded:Tdata):Boolean;
+  var
+    i:LongWord;
+    x,y:Word;
+    fadelvldata:Tdata;
+    revert:Boolean;
+  begin
+    Result:=False;
+
+//    if not (DT_Decoded32 in Self.FDataType) then
+//      Self.DecodeImage;
+    if not (DT_OniReverted in Self.FDataType) then begin
+      revert:=True;
+      Self.RevertImage;
+    end else revert:=False;
+
+    x:=Self.FWidth;
+    y:=Self.FHeight;
+    SetLength(faded,x*y*Self.FDepth div 8);
+    SetLength(fadelvldata,x*y*Self.FDepth div 8);
+    for i:=0 to Length(faded)-1 do begin
+      faded[i]:=Self.FData[i];
+      fadelvldata[i]:=Self.FData[i];
+    end;
+    repeat
+      fadelvldata:=Self.ResizeImage(x,y,fadelvldata);
+      x:=x div 2;
+      y:=y div 2;
+      SetLength(faded,Length(faded)+x*y*Self.FDepth div 8);
+      for i:=0 to Length(fadelvldata)-1 do
+        faded[Length(faded)-x*y*Self.FDepth div 8+i]:=fadelvldata[i];
+    until (x=1) or (y=1) or ((x mod 2)=1) or ((y mod 2)=1);
+    if (x>1) and (y>1) then Exit;
+    Result:=True;
+
+    if revert then
+      Self.RevertImage;
+  end;
+
+
+end.
Index: /oup/releases/0.32a/src/Unit7_txmpreplace.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit7_txmpreplace.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit7_txmpreplace.dfm	(revision 8)
@@ -0,0 +1,179 @@
+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
+  OnCreate = FormCreate
+  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 = 'MIP Mapping'
+      TabOrder = 2
+    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.32a/src/Unit7_txmpreplace.pas
===================================================================
--- /oup/releases/0.32a/src/Unit7_txmpreplace.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit7_txmpreplace.pas	(revision 8)
@@ -0,0 +1,201 @@
+UNIT Unit7_txmpreplace;
+INTERFACE
+USES
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, ExtCtrls, StdCtrls, StrUtils, Unit2_functions, Unit3_data, Unit6_imgfuncs;
+
+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;
+    panel_txmppreview: TPanel;
+    btn_save: TButton;
+    image_txmppreview: TImage;
+    saved: TSaveDialog;
+    procedure FormCreate(Sender: TObject);
+    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 Recreatelist;
+  PRIVATE
+    OniImage_Old:TOniImage;
+    OniImage_New:TOniImage;
+  PUBLIC
+  END;
+
+VAR
+  Form7: TForm7;
+
+IMPLEMENTATION
+USES Unit1_main, Unit15_Classes;
+{$R *.dfm}
+
+PROCEDURE TForm7.Recreatelist;
+  VAR
+    files:TStringArray;
+    i:LongWord;
+  BEGIN
+    list_txmp.Items.Clear;
+    files:=OniDataConnection.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.list_txmpClick(Sender: TObject);
+  VAR
+    id:LongWord;
+    data:Tdata;
+    mem:TMemoryStream;
+    fadingbyte,depthbyte,storebyte:Byte;
+  BEGIN
+    id:=OniDataConnection.ExtractFileID(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+    OniDataConnection.LoadDatFilePart(id,$88,SizeOf(fadingbyte),@fadingbyte);
+    OniDataConnection.LoadDatFilePart(id,$89,SizeOf(depthbyte),@depthbyte);
+    OniDataConnection.LoadDatFilePart(id,$90,SizeOf(storebyte),@storebyte);
+    check_fading.Checked:=(fadingbyte AND $01)>0;
+    check_transparency.Checked:=(depthbyte AND $04)>0;
+
+    OniImage_Old.LoadFromTXMP(id);
+    data:=OniImage_Old.GetAsBMP;
+    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
+    mem:TMemoryStream;
+    tempd:Tdata;
+  BEGIN
+    IF opend.Execute THEN BEGIN
+      OniImage_New.LoadFromBMP(opend.FileName);
+      tempd:=OniImage_New.GetAsBMP;
+      mem:=TMemoryStream.Create;
+      mem.Write(tempd[0],Length(tempd));
+      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;
+
+    oldsize,newsize:LongWord;
+    old_rawaddr,new_rawaddr:LongWord;
+    oldfading:Byte;
+    tempd:Tdata;
+
+    datbyte:Word;
+  BEGIN
+    IF list_txmp.ItemIndex>=0 THEN BEGIN
+      id:=OniDataConnection.ExtractFileID(list_txmp.Items.Strings[list_txmp.ItemIndex]);
+      OniDataConnection.LoadDatFilePart(id,$88,1,@oldfading);
+      if OniDataConnection.OSisMac then
+        OniDataConnection.UpdateDatFilePart(id,$A0,4,@old_rawaddr)
+      else
+        OniDataConnection.LoadDatFilePart(id,$9C,4,@old_rawaddr);
+
+      IF (OniImage_Old.Width<>OniImage_New.Width) OR (OniImage_Old.Height<>OniImage_New.Height) THEN BEGIN
+        IF MessageBox(Self.Handle,
+                    PChar('Current image and new image have different size'+CrLf+
+                            '(Current: '+IntToStr(OniImage_Old.Width)+'x'+IntToStr(OniImage_Old.Height)+
+                            ' - New: '+IntToStr(OniImage_New.Width)+'x'+IntToStr(OniImage_New.Height)+')'+CrLf+
+                            'Replace anyways?'),
+                    PChar(list_txmp.Items.Strings[list_txmp.ItemIndex]),
+                    MB_YESNO)=IDNO THEN Exit;
+      END;
+
+      oldsize:=OniImage_Old.GetImageDataSize((oldfading and $01)>0);
+
+      IF check_fading.Checked THEN
+        IF NOT OniImage_New.GetMipMappedImage(tempd) THEN
+          IF MessageBox(Self.Handle, PChar('Can not create a MipMapped-image (probably because of a wrong dimension).'+#13+#10+'Do you want to continue without MipMapping?'), PChar('Warning'), MB_YESNO)=ID_YES THEN
+            check_fading.Checked:=False
+          ELSE
+            Exit;
+
+      IF NOT check_fading.Checked THEN
+        tempd:=OniImage_New.GetAsData;
+
+      newsize:=OniImage_New.GetImageDataSize(check_fading.Checked);
+      ShowMessage(IntToStr(newsize));
+
+      IF (newsize>oldsize) AND (OniDataConnection.Backend=ODB_Dat) THEN
+        new_rawaddr:=OniDataConnection.AppendRawFile(OniDataConnection.OSisMac,Length(tempd),tempd)
+      ELSE BEGIN
+        new_rawaddr:=old_rawaddr;
+        OniDataConnection.UpdateRawFile(id,$9C,Length(tempd),tempd);
+      END;
+
+      datbyte:=$00;
+      IF check_fading.Checked THEN datbyte:=datbyte OR $01;
+      OniDataConnection.UpdateDatFilePart(id,$88,1,@datbyte);
+      datbyte:=$10;
+      IF check_transparency.Checked THEN datbyte:=datbyte OR $04;
+      OniDataConnection.UpdateDatFilePart(id,$89,1,@datbyte);
+      OniDataConnection.UpdateDatFilePart(id,$8C,2,@OniImage_New.Width);
+      OniDataConnection.UpdateDatFilePart(id,$8E,2,@OniImage_New.Height);
+      datbyte:=$08;
+      OniDataConnection.UpdateDatFilePart(id,$90,1,@datbyte);
+      if OniDataConnection.OSisMac then
+        OniDataConnection.UpdateDatFilePart(id,$A0,4,@new_rawaddr)
+      else
+        OniDataConnection.UpdateDatFilePart(id,$9C,4,@new_rawaddr);
+
+      ShowMessage('TXMP-image replaced');
+    END;
+  END;
+
+PROCEDURE TForm7.FormClose(Sender: TObject; var Action: TCloseAction);
+  BEGIN
+    OniImage_Old.Free;
+    OniImage_New.Free;
+    Action:=caFree;
+    Form1.close_window(Self.Name);
+  END;
+
+PROCEDURE TForm7.FormCreate(Sender: TObject);
+  BEGIN
+    OniImage_Old:=TOniImage.Create;
+    OniImage_New:=TOniImage.Create;
+  END;
+
+PROCEDURE TForm7.FormActivate(Sender: TObject);
+  BEGIN
+    Form1.SetActiveWindow(Self.Name);
+  END;
+
+PROCEDURE TForm7.btn_saveClick(Sender: TObject);
+  BEGIN
+    IF saved.Execute THEN
+      OniImage_Old.WriteToBMP(saved.FileName);
+  END;
+
+END.
Index: /oup/releases/0.32a/src/Unit8_binedit.dfm
===================================================================
--- /oup/releases/0.32a/src/Unit8_binedit.dfm	(revision 8)
+++ /oup/releases/0.32a/src/Unit8_binedit.dfm	(revision 8)
@@ -0,0 +1,385 @@
+object Form8: TForm8
+  Left = 0
+  Top = 0
+  BorderIcons = [biSystemMenu, biMaximize]
+  Caption = 'Binary .dat-Editor'
+  ClientHeight = 555
+  ClientWidth = 642
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'Tahoma'
+  Font.Style = []
+  FormStyle = fsMDIChild
+  KeyPreview = True
+  OldCreateOrder = False
+  Visible = True
+  WindowState = wsMaximized
+  OnActivate = FormActivate
+  OnClose = FormClose
+  OnCloseQuery = FormCloseQuery
+  OnCreate = FormCreate
+  OnKeyUp = FormKeyUp
+  OnResize = FormResize
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Splitter1: TSplitter
+    Left = 150
+    Top = 0
+    Width = 9
+    Height = 555
+    AutoSnap = False
+    Beveled = True
+    MinSize = 150
+    ExplicitHeight = 423
+  end
+  object panel_data: TPanel
+    Left = 159
+    Top = 0
+    Width = 483
+    Height = 555
+    Align = alClient
+    BevelOuter = bvNone
+    TabOrder = 0
+    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 = 450
+      Width = 483
+      Height = 8
+      Cursor = crVSplit
+      Align = alBottom
+      AutoSnap = False
+      Beveled = True
+      MinSize = 40
+      ExplicitTop = 375
+    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 = []
+      OnKeyUp = hexKeyUp
+      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 value_viewer: TWrapGrid
+      Left = 0
+      Top = 218
+      Width = 483
+      Height = 232
+      Align = alClient
+      ColCount = 1
+      DefaultColWidth = 80
+      DefaultRowHeight = 18
+      FixedCols = 0
+      RowCount = 8
+      FixedRows = 0
+      Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goColSizing]
+      PopupMenu = value_viewer_context
+      TabOrder = 1
+      OnDblClick = value_viewerDblClick
+      OnMouseDown = value_viewerMouseDown
+    end
+    object VST: TVirtualStringTree
+      Left = 0
+      Top = 458
+      Width = 483
+      Height = 97
+      Align = alBottom
+      AnimationDuration = 0
+      AutoExpandDelay = 300
+      BiDiMode = bdLeftToRight
+      Colors.UnfocusedSelectionColor = clGradientActiveCaption
+      Colors.UnfocusedSelectionBorderColor = clGradientActiveCaption
+      Ctl3D = True
+      DragOperations = []
+      DrawSelectionMode = smBlendedRectangle
+      EditDelay = 200
+      Font.Charset = DEFAULT_CHARSET
+      Font.Color = clWindowText
+      Font.Height = -11
+      Font.Name = 'Tahoma'
+      Font.Style = []
+      Header.AutoSizeIndex = 0
+      Header.Font.Charset = DEFAULT_CHARSET
+      Header.Font.Color = clWindowText
+      Header.Font.Height = -11
+      Header.Font.Name = 'Tahoma'
+      Header.Font.Style = []
+      Header.Options = [hoColumnResize, hoDblClickResize, hoDrag, hoVisible]
+      Header.PopupMenu = VTHPopup
+      Header.Style = hsFlatButtons
+      HintAnimation = hatNone
+      HintMode = hmTooltip
+      Indent = 14
+      ParentBiDiMode = False
+      ParentCtl3D = False
+      ParentFont = False
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 2
+      TreeOptions.MiscOptions = [toAcceptOLEDrop, toCheckSupport, toFullRepaintOnResize, toInitOnSave, toToggleOnDblClick, toWheelPanning]
+      TreeOptions.PaintOptions = [toShowButtons, toShowDropmark, toShowHorzGridLines, toShowRoot, toShowTreeLines, toShowVertGridLines, toUseBlendedImages]
+      TreeOptions.SelectionOptions = [toExtendedFocus, toFullRowSelect, toRightClickSelect]
+      OnDblClick = VSTDblClick
+      OnFocusChanged = VSTFocusChanged
+      OnGetText = VSTGetText
+      OnHeaderDragged = VSTHeaderDragged
+      Columns = <
+        item
+          MaxWidth = 300
+          MinWidth = 100
+          Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 0
+          Spacing = 20
+          Width = 150
+          WideText = 'Name'
+          WideHint = 'Name of the item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 1
+          Spacing = 20
+          Width = 85
+          WideText = 'Offset'
+          WideHint = 'Offset of the data-item.'
+        end
+        item
+          MaxWidth = 110
+          MinWidth = 75
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 2
+          Width = 75
+          WideText = 'Type'
+          WideHint = 'Data type of the item.'
+        end
+        item
+          MaxWidth = 250
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 3
+          Width = 100
+          WideText = 'Value'
+          WideHint = 'Value of the item.'
+        end
+        item
+          MaxWidth = 400
+          MinWidth = 80
+          Options = [coDraggable, coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible]
+          Position = 4
+          Width = 400
+          WideText = 'Description'
+        end>
+      WideDefaultText = ''
+    end
+  end
+  object panel_files: TPanel
+    Left = 0
+    Top = 0
+    Width = 150
+    Height = 555
+    Align = alLeft
+    BevelOuter = bvNone
+    TabOrder = 1
+    object Bevel1: TBevel
+      Left = 0
+      Top = 491
+      Width = 150
+      Height = 6
+      Align = alBottom
+      Style = bsRaised
+      ExplicitTop = 359
+    end
+    object list: TListBox
+      Left = 0
+      Top = 0
+      Width = 150
+      Height = 388
+      Align = alClient
+      ItemHeight = 13
+      TabOrder = 0
+      OnClick = listClick
+    end
+    object panel_extension: TPanel
+      Left = 0
+      Top = 388
+      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 = 497
+      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
+  object VTHPopup: TVTHeaderPopupMenu
+    OnColumnChange = VTHPopupColumnChange
+    Left = 200
+    Top = 496
+  end
+end
Index: /oup/releases/0.32a/src/Unit8_binedit.pas
===================================================================
--- /oup/releases/0.32a/src/Unit8_binedit.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit8_binedit.pas	(revision 8)
@@ -0,0 +1,901 @@
+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, Unit15_Classes,
+  Menus, Math, VirtualTrees, VTHeaderPopup;
+
+TYPE
+  TForm8 = Class(TForm)
+    Splitter1: TSplitter;
+    panel_data: TPanel;
+    hex: TMPHexEditor;
+    Splitter2: TSplitter;
+    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;
+    VST: TVirtualStringTree;
+    VTHPopup: TVTHeaderPopupMenu;
+    procedure VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex);
+    procedure VSTDblClick(Sender: TObject);
+    procedure VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+      const Column: TColumnIndex; Visible: Boolean);
+    procedure VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+      OldPosition: Integer);
+    procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+      Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+    procedure hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE LoadDat(_fileid:LongWord);
+    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 FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+    PROCEDURE value_viewerDblClick(Sender: TObject);
+    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 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
+    fileid:LongWord;
+  PUBLIC
+  END;
+
+VAR
+  Form8: TForm8;
+
+IMPLEMENTATION
+{$R *.dfm}
+USES Unit1_main, Unit12_ValueEdit, Unit13_rawedit;
+
+TYPE
+  PNodeData = ^TNodeData;
+  TNodeData = record
+    Caption:String;
+    Offset:LongInt;
+    DataType:Word;
+    Value:String;
+    Description:String;
+  end;
+
+
+function AddVSTEntry(AVST:TCustomVirtualStringTree; ANode:PVirtualNode; ARecord:TNodeData):PVirtualNode;
+  var
+    data:PNodeData;
+  begin
+    Result:=AVST.AddChild(ANode);
+    data:=AVST.GetNodeData(Result);
+    AVST.ValidateNode(Result,False);
+    data^:=ARecord;
+  end;
+
+
+
+PROCEDURE TForm8.LoadDat(_fileid:LongWord);
+  VAR
+    i:LongWord;
+    mem:TMemoryStream;
+    data:Tdata;
+  BEGIN
+    IF hex.Modified THEN BEGIN
+      IF NOT Save THEN BEGIN
+        FOR i:=0 TO list.Count-1 DO BEGIN
+          IF OniDataConnection.ExtractFileID(list.Items.Strings[i])=fileid THEN BEGIN
+            list.ItemIndex:=i;
+            Exit;
+          END;
+        END;
+      END;
+    END;
+    fileid:=_fileid;
+    FOR i:=0 TO list.Count-1 DO
+      IF OniDataConnection.ExtractFileID(list.Items.Strings[i])=fileid THEN BEGIN
+        list.ItemIndex:=i;
+        Break;
+      END;
+    Self.ClearStructViewer;
+    data:=OniDataConnection.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; 
+    END ELSE BEGIN
+      ClearValues;
+      hex.DataSize:=0;
+    END;
+  END;
+
+PROCEDURE TForm8.Recreatelist;
+  VAR
+    i:LongWord;
+    exts:TStringArray;
+  BEGIN
+    combo_extension.Items.Clear;
+    combo_extension.Items.Add('_All files_ ('+IntToStr(OniDataConnection.GetFilesCount)+')');
+    exts:=OniDataConnection.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:TStringArray;
+    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:=OniDataConnection.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);
+  BEGIN
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.check_filternameClick(Sender: TObject);
+  BEGIN
+    edit_filtername.Enabled:=NOT check_filtername.Checked;
+    LoadFileNames;
+  END;
+
+PROCEDURE TForm8.listClick(Sender: TObject);
+  BEGIN
+    LoadDat(OniDataConnection.ExtractFileID(list.Items.Strings[list.ItemIndex]));
+  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]);
+      11: Result:='0x'+IntToHex(OniDataConnection.GetRawInfo(fileid,offset).raw_addr,8);
+      12: Result:=FormatNumber(hex.data[offset+1]+hex.data[offset+2]*256+hex.data[offset+3]*256*256,5,'0');
+      13: Result:=IntToStr(hex.data[offset]);
+      14: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256);
+      15: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256);
+      16: Result:=IntToStr(hex.data[offset]+hex.data[offset+1]*256+hex.data[offset+2]*256*256+hex.data[offset+3]*256*256*256);
+      17: Result:=IntToStr((hex.data[offset+3]) DIV 2);
+      100..300: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-100 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Break;
+          END;
+        END;
+      1000..9999: BEGIN
+          Result:='';
+          FOR i:=1 TO datatype-1000 DO BEGIN
+            IF hex.Data[offset+i-1]>=32 THEN
+              Result:=Result+Chr(hex.Data[offset+i-1])
+            ELSE
+              Result:=Result+'.';
+          END;
+        END;
+      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;
+  VAR
+    i,j:LongWord;
+    pdata: PNodeData;
+    data: TNodeData;
+    node: PVirtualNode;
+    structs: TStructDef;
+  BEGIN
+    VST.BeginUpdate;
+    IF VST.RootNodeCount=0 THEN BEGIN
+      structs:=LoadStructureDefinition(fileid);
+      IF structs.data THEN BEGIN
+        IF Length(structs.Global)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Global) DO BEGIN
+            data.Caption:=structs.Global[i].name;
+            data.Offset:=structs.Global[i].offset;
+            data.DataType:=structs.Global[i].datatype;
+            data.Value:=GetValue(structs.Global[i].datatype, structs.Global[i].offset);
+            data.Description:=structs.Global[i].description;
+            AddVSTEntry(VST, nil, data);
+          END;
+        END;
+        IF Length(structs.Subs)>0 THEN BEGIN
+          FOR i:=0 TO High(structs.Subs) DO BEGIN
+            WITH structs.Subs[i] DO BEGIN
+              IF Length(Entries)>0 THEN BEGIN
+                IF Pos('#',SubName)>0 THEN BEGIN
+                  data.Offset:=HexToLong(MidStr(SubName, Pos('#',SubName)+1, 8));
+                  data.Value:=MidStr(SubName, PosEx('#',SubName,Pos('#',SubName)+1)+1, 8);
+                  data.Caption:=MidStr(SubName, 1, Pos('#',SubName)-1);
+                  data.Description:=SubDesc;
+                END ELSE BEGIN
+                  data.Caption:=SubName;
+                  data.Description:=SubDesc;
+                  data.Offset:=0;
+                  data.Value:='';
+                END;
+                data.DataType:=0;
+                node:=AddVSTEntry(VST, nil, data);
+                data.Description:='';
+                FOR j:=0 TO High(Entries) DO BEGIN
+                  data.Caption:=Entries[j].name;
+                  data.Offset:=Entries[j].offset;
+                  data.DataType:=Entries[j].datatype;
+                  data.Value:=GetValue(Entries[j].datatype, Entries[j].offset);
+                  data.Description:=Entries[j].description;
+                  AddVSTEntry(VST, node, data);
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      IF VST.RootNodeCount>0 THEN
+        VST.FocusedNode:=VST.GetFirst;
+    END ELSE BEGIN
+      Node:=VST.GetFirst;
+      WHILE Assigned(Node) DO BEGIN
+        pdata:=VST.GetNodeData(Node);
+        IF pdata.DataType>0 THEN
+          pdata.Value:=GetValue(pdata.Datatype, pdata.Offset);
+        Node:=VST.GetNext(Node);
+      END;
+    END;
+    VST.EndUpdate;
+  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
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              str:=str+'.';
+            Inc(j);
+          END;
+        END ELSE BEGIN
+          FOR j:=0 TO hex.SelCount-1 DO
+            IF hex.Data[hex.selstart+j]>=32 THEN
+              str:=str+Char(hex.Data[hex.SelStart+j])
+            ELSE
+              IF hex.Data[hex.selstart+j]>0 THEN
+                str:=str+'.'
+              ELSE
+                Break;
+        END;
+        value_viewer.Cells[1,i]:=str;
+      END;
+    END;
+  END;
+
+PROCEDURE TForm8.FormCreate(Sender: TObject);
+  BEGIN
+    Self.Caption:='';
+    fileid:=0;
+    VST.NodeDataSize:=SizeOf(TNodeData);
+    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;
+    value_viewer.ColWidths[1]:=value_viewer.Width-150;
+    hex.Height:=panel_data.Height-215;
+//
+    value_viewer.Font.Charset:=AppSettings.CharSet;
+    VST.Font.Charset:=AppSettings.CharSet;
+    hex.Translation:=tkAsIs;
+    hex.Font.Charset:=AppSettings.CharSet;
+//
+  END;
+
+FUNCTION TForm8.Save:Boolean;
+  VAR
+    mem:TMemoryStream;
+    data:Tdata;
+    i:LongWord;
+  BEGIN
+    CASE MessageBox(Self.Handle,PChar('Save changes to file '+OniDataConnection.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;
+          OniDataConnection.UpdateDatFile(fileid,data);
+          hex.Modified:=False;
+          FOR i:=0 TO hex.Datasize-1 DO hex.ByteChanged[i]:=False;
+          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;
+  BEGIN
+    VST.Clear;
+  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.hexChange(Sender: TObject);
+  BEGIN
+    ClearValues;
+    IF hex.DataSize>0 THEN BEGIN
+      WriteStructureInfos;
+      WriteValues;
+    END;
+  END;
+
+PROCEDURE TForm8.hexKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  VAR
+    temps: String;
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=Ord('C')) THEN BEGIN
+      IF hex.SelCount>0 THEN BEGIN
+        IF hex.InCharField THEN
+          Clipboard.AsText:=hex.SelectionAsText
+        ELSE
+          Clipboard.AsText:=hex.SelectionAsHex;
+      END;
+    END;
+    IF (Shift=[ssCtrl]) AND (Key=Ord('V')) THEN BEGIN
+{      temps:=Clipboard.AsText;
+      IF hex.SelStart+Length(temps)>hex.DataSize THEN
+        SetLength(temps, hex.DataSize-hex.SelStart);
+      hex.Sel
+      hex.SelCount:=Length(temps);
+      hex.ReplaceSelection(temps,Length(temps));
+}    END;
+  END;
+
+PROCEDURE TForm8.hexSelectionChanged(Sender: TObject);
+  VAR
+    selstart:Integer;
+    node:PVirtualNode;
+    pdata:PNodeData;
+  BEGIN
+    IF hex.DataSize>0 THEN BEGIN
+      WriteValues;
+      selstart:=hex.SelStart;
+      IF VST.RootNodeCount>0 THEN BEGIN
+        Node:=VST.GetFirst;
+        WHILE Assigned(Node) DO BEGIN
+          pdata:=VST.GetNodeData(Node);
+          IF pdata.DataType>0 THEN BEGIN
+            IF ((selstart-pdata.Offset)<GetTypeDataLength(pdata.DataType)) AND ((selstart-pdata.Offset)>=0) THEN BEGIN
+              VST.FocusedNode:=Node;
+              VST.Selected[Node]:=True;
+              Break;
+            END;
+          END;
+          Node:=VST.GetNext(Node);
+        END;
+      END;
+    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 (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(fileid).Extension+'|All files|*.*';
+    saved.DefaultExt:=OniDataConnection.GetFileInfo(fileid).Extension;
+    IF saved.Execute THEN BEGIN
+      ExportDatFile(fileid,saved.FileName);
+    END;
+  END;
+
+PROCEDURE TForm8.btn_importClick(Sender: TObject);
+  VAR
+    fs:TFileStream;
+  BEGIN
+    opend.Filter:='Files of matching extension (*.'+OniDataConnection.GetFileInfo(fileid).Extension+')|*.'+OniDataConnection.GetFileInfo(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
+    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.VSTDblClick(Sender: TObject);
+  var
+    node:PVirtualNode;
+    nodedata:PNodeData;
+    id:Integer;
+  begin
+    if VST.FocusedColumn=3 then begin
+      node:=VST.FocusedNode;
+      nodedata:=VST.GetNodeData(node);
+
+      if not (nodedata.datatype in [11,12]) and ((nodedata.DataType<100) or (nodedata.DataType>300)) then begin
+        Form12.MakeVarInput(nodedata.Caption,nodedata.offset,nodedata.datatype,nodedata.value,Self);
+      end else begin
+        if nodedata.DataType=11 then begin
+          if OniDataConnection.GetRawInfo(fileid,nodedata.offset).raw_size>0 then begin
+            if Form1.open_child('rawedit') then begin
+              TForm13(Form1.ActiveMDIChild).LoadRaw(OniDataConnection.GetRawInfo(fileid,nodedata.offset));
+            end;
+          end;
+        end;
+        if nodedata.DataType=12 then begin
+          if (StrToInt(nodedata.Value)<OniDataConnection.GetFilesCount) and
+              (StrToInt(nodedata.Value)>0) and
+              (StrToInt(nodedata.Value)<>fileid) then begin
+            if OniDataConnection.GetFileInfo(StrToInt(nodedata.Value)).Size>0 then begin
+              if Form1.open_child('binedit') then begin
+                TForm8(Form1.ActiveMDIChild).LoadDat(StrToInt(nodedata.Value));
+              end;
+            end else begin
+              ShowMessage('Linked filed is a zero-byte-file');
+            end;
+          end;
+        end;
+        if (nodedata.DataType>=100) and (nodedata.DataType<=300) then begin
+          if Form1.open_child('binedit') then begin
+            TForm8(Form1.ActiveMDIChild).edit_filtername.Text:=nodedata.Value;
+            TForm8(Form1.ActiveMDIChild).check_filtername.Checked:=True;
+            TForm8(Form1.ActiveMDIChild).check_filternameClick(Self);
+          end;
+        end;
+      end;
+
+    end;
+  end;
+
+procedure TForm8.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex);
+  var
+    data:PNodeData;
+  begin
+    data:=VST.GetNodeData(node);
+    IF data.DataType>0 THEN BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+GetTypeDataLength(data.DataType)-1;
+    END ELSE BEGIN
+      hex.SelStart:=data.Offset;
+      hex.SelEnd:=data.Offset+HexToLong(data.Value)-1;
+    END;
+  end;
+
+procedure TForm8.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
+  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
+  var
+    data:PNodeData;
+  begin
+    data := Sender.GetNodeData(Node);
+    CellText := '';
+    if TextType = ttNormal then begin
+      case Column of
+        0: CellText := data.Caption;
+        1:
+          if data.DataType>0 then
+            CellText := '0x'+IntToHex(data.Offset,8)
+          else
+            if data.Offset>0 then
+              CellText := '0x'+IntToHex(data.Offset,8);
+        2:
+          if data.DataType>0 then
+            CellText := GetDataType(data.DataType);
+        3:
+          if data.DataType>0 then
+            CellText := data.Value //GetValue(data.DataType, data.Offset)
+          else
+            if Length(data.Value)>0 then
+              CellText := IntToStr(HexToLong(data.Value))+' Bytes';
+        4:
+          CellText := data.Description;
+      end;
+    end;
+  end;
+
+procedure TForm8.VSTHeaderDragged(Sender: TVTHeader; Column: TColumnIndex;
+  OldPosition: Integer);
+  begin
+    if Sender.Columns.Items[column].Position<1 then
+      Sender.Columns.Items[column].Position:=OldPosition;
+  end;
+
+procedure TForm8.VTHPopupColumnChange(const Sender: TBaseVirtualTree;
+  const Column: TColumnIndex; Visible: Boolean);
+  begin
+    if column=0 then
+      TVirtualStringTree(Sender).Header.Columns.Items[column].Options:=TVirtualStringTree(Sender).Header.Columns.Items[column].Options+[coVisible];
+  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;
+
+PROCEDURE TForm8.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
+  BEGIN
+    IF (Shift=[ssCtrl]) AND (Key=83) THEN
+      IF hex.Modified THEN
+        IF NOT Save THEN
+          Exit;
+  END;
+
+
+END.
Index: /oup/releases/0.32a/src/Unit9_data_structures.pas
===================================================================
--- /oup/releases/0.32a/src/Unit9_data_structures.pas	(revision 8)
+++ /oup/releases/0.32a/src/Unit9_data_structures.pas	(revision 8)
@@ -0,0 +1,476 @@
+UNIT Unit9_data_structures;
+INTERFACE
+USES SysUtils, Classes, Unit3_data, Dialogs, StrUtils;
+
+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
+                      // 11    : raw-addr
+                      // 12    : dat-file-ID
+                      // 13..16: Signed Integer[1..4]
+                      // 17    : level-ID
+                      // 100..300: dat-file-name[0..200]
+                      // 1000..9999: Unused data[0-8999]
+                      // 10000+: string[0+]
+      description:String;
+    END;
+  TStructDefSub=RECORD
+      SubName:String;
+      SubDesc:String;
+      Entries:Array OF TStructure_entry;
+    END;
+  TStructDef=RECORD
+      Data:Boolean;
+      Global:Array OF TStructure_entry;
+      Subs:Array OF TStructDefSub;
+    END;
+  THandler=FUNCTION(fileid:LongWord):TRawList;
+  TRawListHandlers=RECORD
+    Ext:String[4];
+    needed:Boolean;
+    Handler:THandler;
+  END;
+
+VAR
+  RawListHandlers:Array OF TRawListHandlers;
+  Raws:String;
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+FUNCTION GetDataType(typeid:Word):String;
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+
+IMPLEMENTATION
+USES Unit2_functions, Unit15_Classes, Forms;
+
+FUNCTION GetTypeDataLength(datatype:Word):Word;
+  BEGIN
+    CASE datatype OF
+      1..4: Result:=datatype;
+      5..8: Result:=datatype-4;
+      9: Result:=4;
+      10: Result:=1;
+      11: Result:=4;
+      12: Result:=4;
+      13..16: Result:=datatype-12;
+      17: Result:=4;
+      100..300: Result:=datatype-100;
+      1000..9999: Result:=datatype-1000;
+      10000..65535: Result:=datatype-10000;
+    END;
+  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';
+      11: Result:='Raw-Address';
+      12: Result:='.dat-file-ID';
+      13..16: Result:='SignedInt'+IntToStr((typeid-12)*8);
+      17: Result:='LevelID';
+      100..300: Result:='.dat-file-name('+IntToStr(typeid-100)+')';
+      1000..9999: Result:='Unused('+IntToStr(typeid-1000)+')';
+      10000..65535: Result:='String('+IntToStr(typeid-10000)+')';
+    END;
+  END;
+
+
+
+
+FUNCTION AGDB(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT OniDataConnection.OSisMac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+      links:=links*2;
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*4;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*4,4,@link);
+        Result[i].raw_addr:=link;
+        Result[i].raw_size:=0{????????????????????????????????};
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION AKVA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    links:LongWord;
+    i:LongWord;
+  BEGIN
+    IF NOT OniDataConnection.OSisMac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+      SetLength(Result,links);
+      FOR i:=0 TO links-1 DO BEGIN
+        Result[i].src_offset:=$20+i*$74+$24;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*$74+$24,4,@link);
+        Result[i].raw_addr:=link;
+        OniDataConnection.LoadDatFilePart(fileid,$20+i*$74+$28,4,@link);
+        Result[i].raw_size:=link;
+        Result[i].loc_sep:=False;
+      END;
+    END;
+  END;
+FUNCTION BINA(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    OniDataConnection.LoadDatFilePart(fileid,$08,4,@datasize);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=OniDataConnection.OSisMac;
+  END;
+FUNCTION OSBD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$08,4,@datasize);
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    SetLength(Result,1);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=OniDataConnection.OSisMac;
+  END;
+FUNCTION SNDD(fileid:LongWord):TRawList;
+  VAR
+    link:LongWord;
+    datasize:LongWord;
+  BEGIN
+    SetLength(Result,1);
+    IF NOT OniDataConnection.OSisMac THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$40,4,@datasize);
+      OniDataConnection.LoadDatFilePart(fileid,$44,4,@link);
+      Result[0].src_offset:=$44;
+    END ELSE BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$10,4,@datasize);
+      OniDataConnection.LoadDatFilePart(fileid,$14,4,@link);
+      Result[0].src_offset:=$14;
+    END;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=False;
+  END;
+FUNCTION SUBT(fileid:LongWord):TRawList;
+  VAR
+    baselink,lastlink:LongWord;
+    links:LongWord;
+    j,k:LongWord;
+    data:Tdata;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$18,4,@baselink);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,4,@links);
+    IF links>0 THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$20+(links-1)*4,4,@lastlink);
+      SetLength(data,lastlink+1024);
+        TOniDataDat(OniDataConnection).LoadRawOffset(false, baselink,lastlink+1024,data); 
+//      OniDataConnection.LoadRawFile(fileid,$1C,baselink,lastlink+1024,False,@data[0]);
+      k:=0;
+      FOR j:=0 TO 1024 DO BEGIN
+        IF (data[lastlink+j]=$00) OR (j=1024) THEN BEGIN
+          IF j<1024 THEN BEGIN
+            IF k=0 THEN BEGIN
+              k:=1;
+            END ELSE BEGIN
+              SetLength(Result,1);
+              Result[0].src_offset:=$18;
+              Result[0].raw_addr:=baselink;
+              Result[0].raw_size:=lastlink+j;
+              Break;
+            END;
+          END;
+        END;
+      END;
+    END;
+  END;
+FUNCTION TRAM(fileid:LongWord):TRawList;
+  VAR
+    i:Integer;
+    link:LongWord;
+    frames:Word;
+    tempb:Byte;
+    tempw:Word;
+    templ:LongWord;
+    data:Tdata;
+    offset:Word;
+    frame_count:Byte;
+  BEGIN
+    SetLength(Result,13);
+    OniDataConnection.LoadDatFilePart(fileid,$16C,2,@frames);
+    {y-pos}
+    OniDataConnection.LoadDatFilePart(fileid,$0C,4,@link);
+    Result[0].src_offset:=$0C;
+    Result[0].raw_addr:=link;
+    Result[0].raw_size:=frames*4;
+    {x-z-pos}
+    OniDataConnection.LoadDatFilePart(fileid,$10,4,@link);
+    Result[1].src_offset:=$10;
+    Result[1].raw_addr:=link;
+    Result[1].raw_size:=frames*8;
+    {attacks}
+    OniDataConnection.LoadDatFilePart(fileid,$182,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$14,4,@link);
+    Result[2].src_offset:=$14;
+    Result[2].raw_addr:=link;
+    Result[2].raw_size:=tempb*32;
+    {damage}
+    OniDataConnection.LoadDatFilePart(fileid,$183,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$18,4,@link);
+    Result[3].src_offset:=$18;
+    Result[3].raw_addr:=link;
+    Result[3].raw_size:=tempb*8;
+    {motionblur}
+    OniDataConnection.LoadDatFilePart(fileid,$184,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$1C,4,@link);
+    Result[4].src_offset:=$1C;
+    Result[4].raw_addr:=link;
+    Result[4].raw_size:=tempb*8;
+    {shortcut}
+    OniDataConnection.LoadDatFilePart(fileid,$185,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$20,4,@link);
+    Result[5].src_offset:=$20;
+    Result[5].raw_addr:=link;
+    Result[5].raw_size:=tempb*8;
+    {throw}
+    OniDataConnection.LoadDatFilePart(fileid,$24,4,@link);
+    Result[6].src_offset:=$24;
+    Result[6].raw_addr:=link;
+    IF link>0 THEN
+      Result[6].raw_size:=24
+    ELSE
+      Result[6].raw_size:=0;
+    {footstep}
+    OniDataConnection.LoadDatFilePart(fileid,$186,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$28,4,@link);
+    Result[7].src_offset:=$28;
+    Result[7].raw_addr:=link;
+    Result[7].raw_size:=tempb*4;
+    {particle}
+    OniDataConnection.LoadDatFilePart(fileid,$187,1,@tempb);
+    OniDataConnection.LoadDatFilePart(fileid,$2C,4,@link);
+    Result[8].src_offset:=$2C;
+    Result[8].raw_addr:=link;
+    Result[8].raw_size:=tempb*24;
+    {position}
+    OniDataConnection.LoadDatFilePart(fileid,$30,4,@link);
+    Result[9].src_offset:=$30;
+    Result[9].raw_addr:=link;
+    Result[9].raw_size:=frames*8;
+    {particle}
+    OniDataConnection.LoadDatFilePart(fileid,$154,2,@tempw);
+    OniDataConnection.LoadDatFilePart(fileid,$38,4,@link);
+    Result[11].src_offset:=$38;
+    Result[11].raw_addr:=link;
+    Result[11].raw_size:=tempw*34;
+    {extent}
+    OniDataConnection.LoadDatFilePart(fileid,$138,4,@templ);
+    OniDataConnection.LoadDatFilePart(fileid,$13C,4,@link);
+    Result[12].src_offset:=$13C;
+    Result[12].raw_addr:=link;
+    Result[12].raw_size:=templ*12;
+
+    OniDataConnection.LoadDatFilePart(fileid,$34,4,@link);
+    IF link>0 THEN BEGIN
+      OniDataConnection.LoadDatFilePart(fileid,$160,2,@tempw);
+      frame_count:=0;
+      i:=0;
+      SetLength(data,$FFFF);
+      TOniDataDat(OniDataConnection).LoadRawOffset(false,link,$FFFF,data); 
+      offset:=data[$24]+data[$25]*256;
+      WHILE (offset+i<Length(data)) AND (frame_count<frames-1) DO BEGIN
+        Inc(i,tempw);
+        frame_count:=frame_count+data[offset+i];
+        Inc(i);
+      END;
+      IF offset+i<Length(data) THEN BEGIN
+        Inc(i,tempw);
+        Result[10].raw_size:=offset+i;
+      END ELSE BEGIN
+        Result[10].raw_size:=0;
+      END;
+    END;
+    Result[10].src_offset:=$34;
+    Result[10].raw_addr:=link;
+  END;
+FUNCTION TXMP(fileid:LongWord):TRawList;
+  VAR
+    link_pc:LongWord;
+    link_mac:LongWord;
+    x,y:Word;
+    storetype:Byte;
+    datasize:LongWord;
+  BEGIN
+    OniDataConnection.LoadDatFilePart(fileid,$8C,SizeOf(x),@x);
+    OniDataConnection.LoadDatFilePart(fileid,$8E,SizeOf(y),@y);
+    OniDataConnection.LoadDatFilePart(fileid,$90,SizeOf(storetype),@storetype);
+    OniDataConnection.LoadDatFilePart(fileid,$9C,4,@link_pc);
+    OniDataConnection.LoadDatFilePart(fileid,$A0,4,@link_mac);
+    CASE storetype OF
+      0,1,2: datasize:=x*y*2;
+      8: datasize:=x*y*4;
+      9: datasize:=x*y DIV 2;
+    END;
+    SetLength(Result,1);
+    IF NOT OniDataConnection.OSisMac THEN BEGIN
+      Result[0].src_offset:=$9C;
+      Result[0].raw_addr:=link_pc
+    END ELSE BEGIN
+      Result[0].src_offset:=$A0;
+      Result[0].raw_addr:=link_mac;
+    END;
+    Result[0].raw_size:=datasize;
+    Result[0].loc_sep:=OniDataConnection.OSisMac;
+  END;
+
+
+PROCEDURE InsertRawListHandler(ext:String; needed:Boolean; handler:THandler);
+  BEGIN
+    SetLength(RawListHandlers,Length(RawListHandlers)+1);
+    RawListHandlers[High(RawListHandlers)].Ext:=ext;
+    RawListHandlers[High(RawListHandlers)].needed:=needed;
+    RawListHandlers[High(RawListHandlers)].handler:=handler;
+    Raws:=Raws+ext;
+  END;
+
+
+
+FUNCTION LoadStructureDefinition(fileid:LongWord):TStructDef;
+  VAR
+    i:LongWord;
+    current_type:Byte; //0: Global, 1: Undynamic, 2: Dynamic
+    current_base,current_package,current_package_size:LongWord;
+    packages:LongWord;
+    deffile:Text;
+    structentry:TStructure_Entry;
+    fields:TStringArray;
+    filename:String;
+    ext:String[4];
+    temps:String;
+    data:TData;
+  BEGIN
+    SetLength(Result.Global,0);
+    SetLength(Result.Subs,0);
+    Result.Data:=False;
+    ext:=OniDataConnection.GetFileInfo(fileid).Extension;
+    filename:=ExtractFilePath(Application.ExeName)+'\StructDefs\'+ext+'.txt';
+    IF FileExists(filename) THEN BEGIN
+      data:=OniDataConnection.LoadDatFile(fileid);
+      AssignFile(deffile,filename);
+      Reset(deffile);
+      current_type:=0;
+      Result.Data:=True;
+      IF NOT EoF(deffile) THEN BEGIN
+        ReadLn(deffile,temps);
+        WHILE NOT EoF(deffile) DO BEGIN
+          ReadLn(deffile,temps);
+          IF (Length(temps)>0) AND (temps[1]<>'#') THEN BEGIN
+            IF temps[1]='*' THEN BEGIN
+              fields:=Explode(temps,#9);
+              CASE Length(fields) OF
+                1..2: BEGIN
+                     current_type:=1;
+                     current_base:=0;
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                     IF Length(fields)=2 THEN
+                       Result.Subs[High(Result.Subs)].SubDesc:=fields[1];
+                   END;
+                3: BEGIN
+                     current_type:=1;
+                     current_base:=HexToLong(fields[2]);
+                     SetLength(Result.Subs, Length(Result.Subs)+1);
+                     Result.Subs[High(Result.Subs)].SubName:=MidStr(fields[0],2,Length(fields[0])-1);
+                     Result.Subs[High(Result.Subs)].SubDesc:=fields[1];
+                   END;
+                6: BEGIN
+                     current_type:=2;
+                     current_base:=HexToLong(fields[2]);
+                     current_package:=0;
+                     current_package_size:=StrToInt(fields[5]);
+                     IF fields[4][1]<>'$' THEN BEGIN
+                       CASE StrToInt(fields[4]) OF
+                         1: packages:=data[HexToLong(fields[3])];
+                         2: packages:=data[HexToLong(fields[3])]+data[HexToLong(fields[3])+1]*256;
+                         4: packages:=data[HexToLong(fields[3])]+data[HexToLong(fields[3])+1]*256+data[HexToLong(fields[3])+2]*256*256+data[HexToLong(fields[3])+3]*256*256*256;
+                       END;
+                     END ELSE BEGIN
+                       packages:=HexToLong(fields[4]);
+                     END;
+                     SetLength(Result.Subs, Length(Result.Subs)+packages);
+                     FOR current_package:=0 TO packages-1 DO BEGIN
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubName:=
+                           MidStr(fields[0],2,Length(fields[0])-1)+'['+IntToStr(current_package)+']'+
+                           '#'+IntToHex(current_base+current_package*current_package_size,8)+
+                           '#'+IntToHex(current_package_size,8);
+                       Result.Subs[High(Result.Subs)-packages+current_package+1].SubDesc:=
+                           fields[1];
+                     END;
+                   END;
+              END;
+            END ELSE BEGIN
+              fields:=Explode(temps,#9);
+              IF (Length(fields)=3) OR (Length(fields)=4) THEN BEGIN
+                IF NOT AppSettings.HideUnusedData OR ((StrToInt(fields[2])<1000) OR (StrToInt(fields[2])>9999)) THEN BEGIN 
+                  structentry.name:=fields[0];
+                  structentry.datatype:=StrToInt(fields[2]);
+                  IF Length(fields)=4 THEN
+                    structentry.description:=fields[3]
+                  ELSE
+                    structentry.description:='';
+                  IF current_type IN [0,1] THEN BEGIN
+                    structentry.offset:=HexToLong(fields[1])+current_base;
+                    IF Length(Result.Subs)=0 THEN BEGIN
+                      SetLength(Result.Global,Length(Result.Global)+1);
+                      Result.Global[High(Result.Global)]:=structentry;
+                    END ELSE BEGIN
+                      SetLength(Result.Subs[High(Result.Subs)].Entries,Length(Result.Subs[High(Result.Subs)].Entries)+1);
+                      Result.Subs[High(Result.Subs)].Entries[High(Result.Subs[High(Result.Subs)].Entries)]:=structentry;
+                    END;
+                  END ELSE BEGIN
+                    FOR current_package:=0 TO packages-1 DO BEGIN
+                      structentry.offset:=current_base+current_package*current_package_size+HexToLong(fields[1]);
+                      WITH Result.Subs[High(Result.Subs)-packages+current_package+1] DO BEGIN
+                        SetLength(Entries,Length(Entries)+1);
+                        Entries[High(Entries)]:=structentry;
+                      END;
+                    END;
+                  END;
+                END;
+              END;
+            END;
+          END;
+        END;
+      END;
+      CloseFile(deffile);
+    END;
+  END;
+
+
+BEGIN
+  Raws:='';
+//  InsertRawListHandler('AGDB',True,AGDB);
+  InsertRawListHandler('AKVA',True,AKVA);
+  InsertRawListHandler('BINA',True,BINA);
+  InsertRawListHandler('OSBD',True,OSBD);
+  InsertRawListHandler('SNDD',True,SNDD);
+  InsertRawListHandler('SUBT',True,SUBT);
+  InsertRawListHandler('TRAM',True,TRAM);
+  InsertRawListHandler('TXMP',True,TXMP);
+END.
Index: /oup/releases/0.32a/todo.txt
===================================================================
--- /oup/releases/0.32a/todo.txt	(revision 8)
+++ /oup/releases/0.32a/todo.txt	(revision 8)
@@ -0,0 +1,168 @@
+-DB mit MAC-Files (andre offsets in dat für raw-links ...)
+-Faded repacking TXMP
+-32byte paddings
+-Exporters (-> TOniImage etc)
+
+-Export etc: If dest-file exists zZt anhängen, stattdessen neuschreiben?!
+
+-Get files die bestimmten content haben (string etc)
+
+-Cursor Sanduhr bei Wartezeiten (db-access etc)
+
+-HELP
+
+-Hex: Paste
+
+-Datei von einem Tool in andrem Tool öffnen
+
+
+-Persist.dat editor
+
+
+-SELECT [src_id],MIN(datfiles.[name]),SUM(rawmap.[size]) FROM rawmap INNER  JOIN datfiles ON datfiles.[id]=[src_id] GROUP BY [src_id] ORDER BY [src_id] ASC
+
+-Extrahier-Ordner-Option (mit Platzhalter für .dat-Name)
+
+-HELP.hlp
+-About
+
+-BinEdit: Zusatzfunktionen wie: Suche, 
+-BinEdit: Bild/Menu/Button irgendwas zum speichern
+
+-Extractor: Wohin?
+
+-FileCompare: Ergebnis=Tabelle, jede Zeile eine differenz-addresse, spalten = werte an addr. für compared files
+
+-TXMP-Replace: MultiReplace
+
+-Move-Freischalter (Mindestlvl eingabe)
+
+-Löschen einer Datei auf die gelinkt wird: Liste der Links und sicherheitsfrage
+
+-Filebox-Context: Extract etc
+
+-DAT geladen -> Meldung oder sogar "what to do next?"
+-SSG: Levels extrahieren?
+-Pierre: Wie Char-Anims, Char-Models, Levels extrahieren?
+-Language-Files?
+-STRG+C auf Dateilisten etc für kopieren des Namens
+
+-REPACKING: testen lvl0: 690-collisions.txmp einbauen, script: collisions-zeug
+
+#################################################################
+##########                 File-Types                  ##########
+#################################################################
+(3CLA)
+ABNA
+AGDB
+AGQC
+AGQG
+(AGQM)
+AGQR
+AISA
+AITR
+(AIWA)
+AKAA
+AKBA
+AKBP
+AKDA
+AKEV
+AKOT
+AKVA
+BINA
+CBPI
+CBPM
+CONS
+CRSA
+DOOR
+DPge
+(EDIA)
+ENVP
+FILM
+(FXLR)
+(GMAN)
+HPge
+IDXA
+IGHH
+IGPA
+IGPG
+IGSA
+IGSt
+Impt
+IPge
+KeyI
+M3GA
+M3GM
+(M3TA)
+Mtrl
+(NMSA)
+OBAN
+OBDC
+(OBLS)
+OBOA
+OFGA
+ONCC
+ONCP
+ONCV
+ONFA
+ONGS
+ONIA
+ONLD
+ONLV
+ONMA
+ONOA
+ONSA
+ONSK
+ONTA
+ONVL
+ONWC
+OPge
+OSBD
+OTIT
+OTLF
+PLEA
+PNTA
+PSpc
+PSpL
+PSUI
+QTNA
+(QUDA)
+SNDD
+StNA
+SUBT
+(TMFA)
+(TMRA)
+TRAC
+TRAM
+TRAS
+TRBS
+TRCM
+(TRFT)
+TRGA
+TRGE
+TRIA
+TRIG
+TRMA
+TRSC
+TRTA
+TSFF
+TSFL
+TSFT
+TSGA
+TStr
+TURR
+TXAN
+TXCA
+TXMA
+TXMB
+TXMP
+(TXPC)
+TxtC
+(UUEA)
+(UVDL)
+VCRA
+WMCL
+WMDD
+WMM_
+WMMB
+WPge
Index: /oup/structdefs/06-04-19/AISA.txt
===================================================================
--- /oup/structdefs/06-04-19/AISA.txt	(revision 8)
+++ /oup/structdefs/06-04-19/AISA.txt	(revision 8)
@@ -0,0 +1,27 @@
+AI Character Setup Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	352
+Unknown	$00	10032	unknown; always zero; maybe space for notes
+Charcter id	$20	2	Id of the character, which you can spawn with the script command "chr_create"
+Flag id	$22	2	Od of the flag, where Oni spawns the character (works only, if the flag exits; look to Flag.BINA for a flag list)
+Unknown	$24	2	Unknown
+Unknown	$26	2	Unknown
+ONCC-link	$28	12	Link to the Character Class
+Unknown	$2C	4	Unknown; always the same
+Unknown	$30	10032	Unknown; never used in Oni
+Spawn function	$50	10032	Name of the function, which is called up when Oni spawns the character
+Lose function	$70	10032	Name of the function, which is called up when the character dies
+Alert function	$90	10032	Name of the function, which is called up when the character notices the player
+Unknown	$B0	10032	Unknown; never used in Oni
+Hit function	$D0	10032	Name of the function, which is called up when someone hits the character the first time
+Health = 1 function	$F0	10032	Name of the function, which is called up when the health of the character is equal 1
+Reload function	$110	10032	Name of the function, which is called up when the character reloads its weapon with its last ammo/cell; works only, if the character has some ammo/cells when Oni spawns it
+Unknown	$130	10032	Unknown; never used in Oni
+ONWC-link	$150	12	Link to the Weapon Class; used to give the charcater a weapon
+Unknown	$154	2	Unknown
+Unknown	$156	14	Unknown; always the same
+Unknown	$158	4	Unknown; always the same
+Unknown	$15C	4	Unknown; always the same
Index: /oup/structdefs/06-04-19/AKEV.txt
===================================================================
--- /oup/structdefs/06-04-19/AKEV.txt	(revision 8)
+++ /oup/structdefs/06-04-19/AKEV.txt	(revision 8)
@@ -0,0 +1,28 @@
+Environment
+File id	$00	12	File id
+Level id	$04	17	Level id
+PNTA-link	$08	12	Link to the 3D Point Array
+PLEA-link	$0C	12	Link to the Plane Equation Array
+TXCA-link	$10	12	Link to the Texture Coordinate Array
+AGQG-link	$14	12	Link to the Gunk Quad General Array
+AGQR-link	$18	12	Link to the Gunk Quad Render Array
+AGQC-link	$1C	12	Link to the Gunk Quad Collision Array
+AGDB-link	$20	12	Link to the Gunk Quad Debug Array
+TXMA-link	$24	12	Link to the Texture Map Array
+AKVA-link	$28	12	Link to the BNV Node Array
+AKBA-link	$2C	12	Link to the Side Array
+IDXA-link	$30	12	Link to the Index Array
+IDXA-link	$34	12	Link to the Index Array
+AKBP-link	$38	12	Link to the BSP Node Array
+ABNA-link	$3C	12	Link to the BSP Tree Node Array
+AKOT-link	$40	12	Link to the Oct Tree
+AKAA-link	$44	12	Link to the Adjacency Array
+AKDA-link	$48	12	Link to the Door Frame Array
+Neg. x-coordinate	$4C	9	Maximal negative x-coordinate of the level model
+Neg. y-coordinate	$50	9	Maximal negative y-coordinate of the level model
+Neg. z-coordinate	$54	9	Maximal negative z-coordinate (height) of the level model
+Pos. x-coordinate	$58	9	Maximal positive x-coordinate of the level model
+Pos. y-coordinate	$5C	9	Maximal positive y-coordinate (height) of the level model
+Pos. z-coordinate	$60	9	Maximal positive z-coordinate of the level model
+Not used	$64	1024	Not used
+Unknown	$7C	9	Unknown; maybe the tolerance
Index: /oup/structdefs/06-04-19/DOOR.txt
===================================================================
--- /oup/structdefs/06-04-19/DOOR.txt	(revision 8)
+++ /oup/structdefs/06-04-19/DOOR.txt	(revision 8)
@@ -0,0 +1,15 @@
+DOOR File
+File id	$00	12	File id
+Level id	$04	17	Level id
+OFGA-link	$08	12	Link to the Object Furn Geom Array
+Unknown	$0C	4	Unknown; maybe a canceled link; always the same
+OBAN-link	$10	12	Link to the Object Animation
+Unknown	$14	9	Unknown; always the same
+Unknown	$18	4	Unknown; always the same
+Unknown	$1C	16	Unknown; always the same
+Unknown	$20	9	Unknown; always the same
+Door open sound	$24	132	Reference to an OSBD file of level 0
+Door close sound	$44	132	Reference to an OSBD file of level 0
+Unknown	$64	4	Unknown
+Unknown	$68	4	Unknown
+Not useed	$6C	1020	Not used
Index: /oup/structdefs/06-04-19/IGPA.txt
===================================================================
--- /oup/structdefs/06-04-19/IGPA.txt	(revision 8)
+++ /oup/structdefs/06-04-19/IGPA.txt	(revision 8)
@@ -0,0 +1,7 @@
+IGUI (In-Game User Interface) Page Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+IGPG-link	$00	12	Link to the In-Game User Interface Page
Index: /oup/structdefs/06-04-19/IGPG.txt
===================================================================
--- /oup/structdefs/06-04-19/IGPG.txt	(revision 8)
+++ /oup/structdefs/06-04-19/IGPG.txt	(revision 8)
@@ -0,0 +1,15 @@
+IGUI (In-Game User Interface) Page
+File id	$00	12	File id
+Level id	$04	17	Level id
+TSFF-link	$08	12	Link to the Font Family
+Font option	$0C	4	Font option
+Font color B	$10	1	Font color - blue part
+Font color G	$11	1	Font color - green part
+Font color R	$12	1	Font color - red part
+Unknown	$13	1	Unknown
+Font size	$14	2	Font size of the text; maybe the minimal font size in connection to the screen resolution
+Enabler	$16	2	Enables the previous entries; it's a bitset
+PSpc-link	$18	12	Link to the Part Specification
+IGSA-link	$1C	12	Link to the In-Game User Interface String Array
+IGSA-link	$20	12	Link to the In-Game User Interface String Array
+Not used	$24	1028	Not used
Index: /oup/structdefs/06-04-19/IGSA.txt
===================================================================
--- /oup/structdefs/06-04-19/IGSA.txt	(revision 8)
+++ /oup/structdefs/06-04-19/IGSA.txt	(revision 8)
@@ -0,0 +1,7 @@
+IGUI (In-Game User Interface) String Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+IGSt-link	$00	12	Link to the In-Game User Interface String
Index: /oup/structdefs/06-04-19/ONCC.txt
===================================================================
--- /oup/structdefs/06-04-19/ONCC.txt	(revision 8)
+++ /oup/structdefs/06-04-19/ONCC.txt	(revision 8)
@@ -0,0 +1,277 @@
+Oni character class
+File id	$00	12	File id
+Level id	$04	17	Level id
+TXMP-link	$28	12	Shadow texture
+Shadow height 5 	$2C	9	Height, where the shadow fades out completely
+Shadow height 4	$30	9	Height, where the diameter of the shadow decreases and the shadow fades out half
+Shadow height 3	$34	9	Height, where the diameter of the shadow decreases
+Shadow height 2	$38	9	Height, where the diameter of the shadow decreases
+Shadow height 1	$3C	9	Height, where the diameter of the shadow decreases
+Shadow option 1	$40	2	Transparency of the shadow for the first part of a jump
+Shadow option 2	$42	2	Transparency of the shadow for the second part of a jump
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use a hypo
+Hurt light sound	$98	132	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	132	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	132	Reference to an OSBD file of level 0
+Death sound	$F8	132	Reference to an OSBD file of level 0
+Rotation factor	$12C	9	Rotation factor * 360 degrees = possible rotation per frame or animation
+Taunt sound query	$2B0	1	0 = not used; 100 = used
+Alert sound query	$2B1	1	0 = not used; 100 = used
+Startle sound query	$2B2	1	0 = not used; 100 = used
+Check body sound query	$2B3	1	0 = not used; 100 = used
+Pursue sound query	$2B4	1	0 = not used; 100 = used
+Cower sound query	$2B5	1	0 = not used; 100 = used
+Punch heavy sound query	$2B6	1	0 = not used; 100 = used
+Kich heavy sound query	$2B7	1	0 = not used; 100 = used
+Super3 sound query	$2B8	1	0 = not used; 100 = used
+Super4 sound query	$2B9	1	0 = not used; 100 = used
+Taunt sound	$2BC	132	Reference to a SNDD file of level 0
+Alert sound	$2DC	132	Reference to a SNDD file of level 0
+Startle sound	$2FC	132	Reference to a SNDD file of level 0
+Check body sound	$31C	132	Reference to a SNDD file of level 0
+Pursue sound	$33C	132	Reference to a SNDD file of level 0
+Cower sound	$35C	132	Reference to a SNDD file of level 0
+Punch heavy sound	$37C	132	Reference to a SNDD file of level 0
+Kick heavy sound	$39C	132	Reference to a SNDD file of level 0
+Super3 sound	$3BC	132	Reference to a SNDD file of level 0
+Super4 sound	$3DC	132	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV-link	$434	12	Character varient link
+ONCP-link	$438	12	Character particle array link; useless?
+ONIA-link	$43C	12	Character impact array link; useless?
+Footstep walk impact	$454	230	Reference to an Impt file of level 0
+Footstep run impact	$4D6	230	Reference to an Impt file of level 0
+Footstep crouch impact	$558	230	Reference to an Impt file of level 0
+Fall slide impact	$5DA	230	Reference to an Impt file of level 0
+Fall land impact	$65C	230	Reference to an Impt file of level 0
+Fall land hard impact	$6DE	230	Reference to an Impt file of level 0
+Fall knockdown impact	$760	230	Reference to an Impt file of level 0
+Fall knockdown impact	$7E2	230	Reference to an Impt file of level 0
+Fall knockdown impact	$864	230	Reference to an Impt file of level 0
+Footstep turn impact	$8E6	230	Reference to an Impt file of level 0
+Footstep run start impact	$968	230	Reference to an Impt file of level 0
+Footstep single step impact	$9EA	230	Reference to an Impt file of level 0
+Footstep run stop impact	$A6C	230	Reference to an Impt file of level 0
+Footstep walk stop impact	$AEE	230	Reference to an Impt file of level 0
+Footstep run sprint impact	$B70	230	Reference to an Impt file of level 0
+Special death particles	$BF4	164	Reference to a 3Dparticle.BINA file of level 0; only the mad bomber use it
+TRBS-link	$C3C	12	Body set link
+TRMA-link	$C40	12	Texture map array link
+CBPM-link	$C44	12	Body part material link
+CBPI-link	$C48	12	Body part impact link
+Peace timer	$C4C	4	Peace timer in 1/60 seconds; after that time the character switches back from fight to peace mode
+First idle timer	$C50	4	First idle timer in 1/60 seconds; after that time Oni plays a special idle animation
+Second idle timer	$C54	4	Second idle timer in 1/60 seconds; after that time Oni plays a special idle animation
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Basic health	$C5C	4	Unknown; always the same
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC-link	$C88	8	Animation collection link
+TRSC-link	$C8C	8	Screen (aiming) collection link
+
+*Unknown
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	2	Unknown
+Unknown	$1E	2	Unknown
+Unknown	$20	9	Unknown
+Unknown	$24	9	Unknown
+Unknown	$44	9	Unknown; always the same
+Unknown	$48	1	Unknown
+Unknown	$49	1	Unknown; always the same
+Unknown	$4C	9	Unknown; always the same
+Unknown	$50	9	Unknown; always the same
+Unknown	$54	9	Unknown; always the same
+Unknown	$58	9	Unknown; always the same
+Unknown	$5C	9	Unknown; always the same
+Unknown	$60	9	Unknown; always the same
+Unknown	$68	9	Unknown; always the same
+Unknown	$6C	9	Unknown; always the same
+Unknown	$70	9	Unknown; always the same
+Unknown	$74	9	Unknown; always the same
+Unknown	$78	9	Unknown; always the same
+Unknown	$7C	2	Unknown; always the same
+Unknown	$7E	2	Unknown; always the same
+Unknown	$80	2	Unknown; always the same
+Unknown	$82	2	Unknown; always the same
+Unknown	$84	2	Unknown; always the same
+Unknown	$86	2	Unknown; always the same
+Unknown	$88	2	Unknown; always the same
+Unknown	$8A	2	Unknown; always the same
+Unknown	$8C	2	Unknown; always the same
+Unknown	$8E	2	Unknown; always the same
+Unknown	$90	2	Unknown; always the same
+Unknown	$92	1	Unknown; always the same
+Unknown	$94	9	Unknown; always the same
+Unknown	$118	4	Unknown; always the same
+Unknown	$11C	4	Unknown; always the same
+Unknown	$120	4	Unknown; always the same
+Unknown	$124	4	Unknown; always the same
+Unknown	$128	4	Unknown
+Unknown	$130	2	Unknown
+Unknown	$132	2	Unknown
+Unknown	$134	4	Unknown
+Unknown	$138	9	Unknown
+Unknown	$13C	9	Unknown
+Unknown	$140	9	Unknown; always the same
+Unknown	$144	9	Unknown; always the same
+Unknown	$148	9	Unknown; always the same
+Unknown	$14C	4	Unknown
+Unknown	$150	4	Unknown
+Unknown	$154	4	Unknown
+Unknown	$158	4	Unknown
+Unknown	$404	9	Unknown
+Unknown	$408	9	Unknown
+Unknown	$40C	9	Unknown
+Unknown	$410	9	Unknown; always the same
+Unknown	$414	9	Unknown; always the same
+Unknown	$418	4	Unknown; always the same
+Unknown	$41C	4	Unknown; always the same
+Unknown	$420	4	Unknown; always the same
+Unknown	$424	4	Unknown; always the same
+Unknown	$428	4	Unknown; always the same
+Unknown	$42C	4	Unknown; always the same
+Unknown	$430	9	Unknown; always the same
+Unknown	$294	4	Unknown; always the same
+Unknown	$298	4	Unknown; always the same
+Unknown	$29C	4	Unknown; always the same
+Unknown	$2A0	4	Unknown; always the same
+Unknown	$2A4	4	Unknown
+Unknown	$2A8	4	Unknown
+Unknown	$2AC	2	Unknown
+Unknown	$2AE	2	Unknown
+Unknown	$440	4	Unknown; maybe a canceled link; always the same
+Unknown	$444	10016	Maybe the weight of the character?
+Unknown	$BF2	2	Unknown; always the same; maybe only a filler
+Unknown	$C34	4	Unknown; maybe a canceled link; always the same
+Unknown	$C38	4	Unknown; maybe a canceled link; always the same
+Unknown	$C68	9	Unknown; always the same
+Unknown	$C6C	9	Unknown; always the same
+Unknown	$C70	9	Unknown
+Unknown	$C74	9	Unknown
+Unknown	$C78	9	Unknown; always the same
+Unknown	$C7C	9	Unknown; always the same
+Unknown	$C80	9	Unknown; always the same
+Unknown	$C84	9	Unknown
+Unknown	$C90	2	Unknown; always the same
+Unknown	$C92	2	Unknown; only the mad bomber use it
+Unknown	$C94	1	Unknown
+Unknown	$C95	1	Unknown
+Unknown	$C96	1	Unknown
+Unknown	$C97	1	Unknown
+
+*Unused
+Not used	$4A	1002	Not used
+Not used	$66	1002	Not used
+Not used	$93	1001	Not used
+Not useed	$C98	1008	Not used
+
+
+*Unknown Block1
+Block 1 - Unknown	$15C	9	Unknown
+Block 1 - Unknown	$160	9	Unknown
+Block 1 - Unknown	$164	9	Unknown; always the same
+Block 1 - Unknown	$168	9	Unknown
+Block 1 - Unknown	$16C	9	Unknown
+Block 1 - Unknown	$170	2	Unknown; always the same
+Block 1 - Unknown	$172	2	Unknown; always the same
+*Unknown Block2
+Block 2 - Unknown	$174	9	Unknown
+Block 2 - Unknown	$178	9	Unknown
+Block 2 - Unknown	$17C	9	Unknown
+Block 2 - Unknown	$180	9	Unknown
+Block 2 - Unknown	$184	9	Unknown
+Block 2 - Unknown	$188	2	Unknown; always the same
+Block 2 - Unknown	$18A	2	Unknown; always the same
+*Unknown Block3
+Block 3 - Unknown	$18C	9	Unknown
+Block 3 - Unknown	$190	9	Unknown
+Block 3 - Unknown	$194	9	Unknown; always the same
+Block 3 - Unknown	$198	9	Unknown
+Block 3 - Unknown	$19C	9	Unknown
+Block 3 - Unknown	$1A0	2	Unknown; always the same
+Block 3 - Unknown	$1A2	2	Unknown; always the same
+*Unknown Block4
+Block 4 - Unknown	$1A4	9	Unknown
+Block 4 - Unknown	$1A8	9	Unknown
+Block 4 - Unknown	$1AC	9	Unknown; always the same
+Block 4 - Unknown	$1B0	9	Unknown
+Block 4 - Unknown	$1B4	9	Unknown
+Block 4 - Unknown	$1B8	2	Unknown
+Block 4 - Unknown	$1BA	2	Unknown
+*Unknown Block5
+Block 5 - Unknown	$1BC	9	Unknown; always the same
+Block 5 - Unknown	$1C0	9	Unknown
+Block 5 - Unknown	$1C4	9	Unknown
+Block 5 - Unknown	$1C8	9	Unknown
+Block 5 - Unknown	$1CC	9	Unknown
+Block 5 - Unknown	$1D0	2	Unknown
+Block 5 - Unknown	$1D2	2	Unknown
+*Unknown Block6
+Block 6 - Unknown	$1D4	9	Unknown
+Block 6 - Unknown	$1D8	9	Unknown
+Block 6 - Unknown	$1DC	9	Unknown
+Block 6 - Unknown	$1E0	9	Unknown
+Block 6 - Unknown	$1E4	9	Unknown
+Block 6 - Unknown	$1E8	2	Unknown
+Block 6 - Unknown	$1EA	2	Unknown
+*Unknown Block7
+Block 7 - Unknown	$1EC	9	Unknown; always the same
+Block 7 - Unknown	$1F0	9	Unknown
+Block 7 - Unknown	$1F4	9	Unknown
+Block 7 - Unknown	$1F8	9	Unknown
+Block 7 - Unknown	$1FC	9	Unknown; always the same
+Block 7 - Unknown	$200	2	Unknown; always the same
+Block 7 - Unknown	$202	2	Unknown; always the same
+*Unknown Block8
+Block 8 - Unknown	$204	9	Unknown
+Block 8 - Unknown	$208	9	Unknown
+Block 8 - Unknown	$20C	9	Unknown
+Block 8 - Unknown	$210	9	Unknown; always the same
+Block 8 - Unknown	$214	9	Unknown
+Block 8 - Unknown	$218	2	Unknown
+Block 8 - Unknown	$21A	2	Unknown
+*Unknown Block9
+Block 9 - Unknown	$21C	9	Unknown
+Block 9 - Unknown	$220	9	Unknown
+Block 9 - Unknown	$224	9	Unknown
+Block 9 - Unknown	$228	9	Unknown
+Block 9 - Unknown	$22C	9	Unknown
+Block 9 - Unknown	$230	2	Unknown
+Block 9 - Unknown	$232	2	Unknown
+*Unknown Block10
+Block 10 - Unknown	$234	9	Unknown
+Block 10 - Unknown	$238	9	Unknown
+Block 10 - Unknown	$23C	9	Unknown
+Block 10 - Unknown	$240	9	Unknown
+Block 10 - Unknown	$244	9	Unknown
+Block 10 - Unknown	$248	2	Unknown
+Block 10 - Unknown	$24A	2	Unknown
+*Unknown Block11
+Block 11 - Unknown	$24C	9	Unknown
+Block 11 - Unknown	$250	9	Unknown
+Block 11 - Unknown	$254	9	Unknown; always the same
+Block 11 - Unknown	$258	9	Unknown
+Block 11 - Unknown	$25C	9	Unknown; always the same
+Block 11 - Unknown	$260	2	Unknown; always the same
+Block 11 - Unknown	$262	2	Unknown; always the same
+*Unknown Block12
+Block 12 - Unknown	$264	9	Unknown
+Block 12 - Unknown	$268	9	Unknown
+Block 12 - Unknown	$26C	9	Unknown; always the same
+Block 12 - Unknown	$270	9	Unknown
+Block 12 - Unknown	$274	9	Unknown; always the same
+Block 12 - Unknown	$278	2	Unknown; always the same
+Block 12 - Unknown	$27A	2	Unknown; always the same
+*Unknown Block13
+Block 13 - Unknown	$27C	9	Unknown
+Block 13 - Unknown	$280	9	Unknown
+Block 13 - Unknown	$284	9	Unknown; always the same
+Block 13 - Unknown	$288	9	Unknown
+Block 13 - Unknown	$28C	9	Unknown; always the same
+Block 13 - Unknown	$290	2	Unknown; always the same
+Block 13 - Unknown	$292	2	Unknown; always the same
Index: /oup/structdefs/06-04-19/ONLD.txt
===================================================================
--- /oup/structdefs/06-04-19/ONLD.txt	(revision 8)
+++ /oup/structdefs/06-04-19/ONLD.txt	(revision 8)
@@ -0,0 +1,7 @@
+Oni Level Descriptor
+File id	$00	12	File id
+Level id	$04	17	Level id
+Current level	$08	2	Id of current level
+Next level	$0A	2	Id of the level that follows
+Level name	$0C	10064	Name of the level; you'll find it in the list, when you load a level
+Not used	$4C	1020	Not used
Index: /oup/structdefs/06-04-19/ONLV.txt
===================================================================
--- /oup/structdefs/06-04-19/ONLV.txt	(revision 8)
+++ /oup/structdefs/06-04-19/ONLV.txt	(revision 8)
@@ -0,0 +1,20 @@
+Oni Level Descriptor
+File id	$00	12	File id
+Level id	$04	17	Level id
+Level name	$08	10064	Name of the level
+AKEV-Link	$48	12	Link to the Environment
+OBOA-Link	$4C	12	Link to the Starting Object Array
+ONMA-Link	$50	12	Link to the Imported Marker Node Array
+ONFA-Link	$54	12	Link to the Imported Flag Node Array
+ONTA-Link	$58	12	Link to the Trigger Array
+ONSK-Link	$5C	12	Link to the Sky Class
+Unknown	$60	12	Unknown; maybe a canceled link; always the same
+AISA-Link	$64	12	Link to the AI Character Setup Array
+AITR-Link	$68	12	Link to the AI Script Trigger Array
+ONSA-Link	$6C	12	Link to the Imported Spawn Array
+OBDC-Link	$70	12	Link to the Door Class Array
+ONOA-Link	$74	12	Link to the Object Gunk Array
+ENVP-Link	$78	12	Link to the Environment Particle Array
+Not used	$7C	1644	Not used
+CRSA-Link	$300	12	Link to the Corpse Array
+Not used	$304	1028	Not used
Index: /oup/structdefs/06-04-19/PSPC.txt
===================================================================
--- /oup/structdefs/06-04-19/PSPC.txt	(revision 8)
+++ /oup/structdefs/06-04-19/PSPC.txt	(revision 8)
@@ -0,0 +1,43 @@
+Particle Specification (coordinates of UI element in texture) (see pspc.png)
+
+ID	$00	12
+LevelID	$04	17
+LFT-LT	$08	2	LT Left
+TOP-LT	$0A	2	LT Top
+LFT-HL	$0C	2	HL Left (rubber)
+TOP-HL	$0E	2	HL Top (rubber)
+LFT-LB	$10	2	LB Left
+TOP-LB	$12	2	LB Top
+LFT-VT	$14	2	VT Left (rubber)
+TOP-VT	$16	2	VT Top (rubber)
+LFT-CC	$18	2	CC Left (rubber)
+TOP-CC	$1A	2	CC Top (rubber)
+LFT-VB	$1C	2	VB Left (rubber)
+TOP-VB	$1E	2	VB Top (rubber)
+LFT-RT	$20	2	RT Left
+TOP-RT	$22	2	RT Top
+LFT-HR	$24	2	HR Left (rubber)
+TOP-HR	$26	2	HR Top (rubber)
+LFT-RB	$28	2	RB Left
+TOP-RB	$2A	2	RB Top
+
+RGH-LT	$2C	2	LT Right
+BTM-LT	$2E	2	LT Bottom
+RGH-HL	$30	2	HL Right (rubber)
+BTM-HL	$32	2	HL Bottom (rubber)
+RGH-LB	$34	2	LB Right
+BTM-LB	$36	2	LB Bottom
+RGH-VT	$38	2	VT Right (rubber)
+BTM-VT	$3A	2	VT Bottom (rubber)
+RGH-CC	$3C	2	CC Right (rubber)
+BTM-CC	$3E	2	CC Bottom (rubber)
+RGH-VB	$40	2	VB Right (rubber)
+BTM-VB	$42	2	VB Bottom (rubber)
+RGH-RT	$44	2	RT Right
+BTM-RT	$46	2	RT Bottom
+RGH-HR	$48	2	HR Right (rubber)
+BTM-HR	$4A	2	HR Bottom (rubber)
+RGH-RB	$4C	2	RB Right
+BTM-RB	$4E	2	RB Bottom
+TXMP-Link	$50	12	Corresponding texture
+
Index: /oup/structdefs/06-04-19/PSpL.txt
===================================================================
--- /oup/structdefs/06-04-19/PSpL.txt	(revision 8)
+++ /oup/structdefs/06-04-19/PSpL.txt	(revision 8)
@@ -0,0 +1,8 @@
+Part Specification List
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	8
+Unknown	$00	4	Unknown
+PSpc-link	$04	12	Link to the Part Specification
Index: /oup/structdefs/06-04-19/SUBT.txt
===================================================================
--- /oup/structdefs/06-04-19/SUBT.txt	(revision 8)
+++ /oup/structdefs/06-04-19/SUBT.txt	(revision 8)
@@ -0,0 +1,8 @@
+Subtitles
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1016	Not used
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Packages	$1C	4	Amount of packages that follow
+*Packages		$20	$1C	4	4
+Raw-link	$0	11	Start position of the subtitle in the raw file
Index: /oup/structdefs/06-04-19/TRAM.txt
===================================================================
--- /oup/structdefs/06-04-19/TRAM.txt	(revision 8)
+++ /oup/structdefs/06-04-19/TRAM.txt	(revision 8)
@@ -0,0 +1,126 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+File id	$00	12	File id
+Level id	$04	17	Level id
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	4	Flags; it seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	4	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	4	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	4	Used parts; used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	4	Replace parts; used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	14	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	116	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	14	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
+
+
+*Unknown
+Unknown	$08	4	Unknown; always zero
+Unknown	$58	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$5C	9	Unknown; always 1,000,000,000 if the attack part doesn't exist
+Unknown	$60	9	Unknown; always -1,000,000,000 if the attack part doesn't exist
+Unknown	$64	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$68	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$6C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$70	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$74	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$78	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$7C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$80	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$84	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$88	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$8C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$90	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$94	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$98	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$9C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$AC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$BC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$CC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$DC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$EC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$F0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$F4	14	Unknown; always -1 if the attack part doesn't exist
+Unknown	$F6	2	Unknown; always zero
+Unknown	$F8	9	Unknown
+Unknown	$FC	9	Unknown
+Unknown	$100	9	Unknown
+Unknown	$104	9	Unknown
+Unknown	$108	9	Unknown
+Unknown	$10C	9	Unknown
+Unknown	$110	9	Unknown
+Unknown	$114	14	Unknown
+Unknown	$116	1	Unknown
+Unknown	$117	1	Unknown
+Unknown	$118	9	Unknown
+Unknown	$11C	9	Unknown
+Unknown	$120	9	Unknown
+Unknown	$124	9	Unknown
+Unknown	$128	9	Unknown
+Unknown	$12C	9	Unknown
+Unknown	$130	9	Unknown
+Unknown	$134	8	Unknown; always zero
+Unknown	$154	2	Unknown; it seems that it belongs to the sound part
+Unknown	$156	2	Unknown
+Unknown	$158	2	Unknown
+Unknown	$15A	2	Unknown
+Unknown	$15C	2	Unknown
+Unknown	$180	1	Unknown
+Unknown	$181	1	Unknown
+
+
+*Unused
+Not used	$188	10024	Not used
+
Index: /oup/structdefs/06-04-19/TXAN.txt
===================================================================
--- /oup/structdefs/06-04-19/TXAN.txt	(revision 8)
+++ /oup/structdefs/06-04-19/TXAN.txt	(revision 8)
@@ -0,0 +1,11 @@
+Texture Animation
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1012	Not used
+Loop speed	$14	2	Loop speed
+Unknown	$16	2	Unknown
+Unknown	$18	2	Unknown
+Not used	$1A	1002	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+TXMP link	$00	12	Image which is used for the texture animation
Index: /oup/structdefs/06-04-19/TXMP.txt
===================================================================
--- /oup/structdefs/06-04-19/TXMP.txt	(revision 8)
+++ /oup/structdefs/06-04-19/TXMP.txt	(revision 8)
@@ -0,0 +1,15 @@
+Texture
+ID	$00	12	ID of this file
+LevelID	$04	17	ID of the level this file is in
+FileName	$08	10128	Name of the texture
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Unknown	$8A	2	Unknown; always zero
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	12	Link to the TXAN-file; only used if the texture is the first image of an texture animation
+TXMP-Link	$98	12	Link to another TXMP-file; only used in connection with shade vertex effects
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
+Not used	$A4	1028	Not used
Index: /oup/structdefs/06-04-19/TxtC.txt
===================================================================
--- /oup/structdefs/06-04-19/TxtC.txt	(revision 8)
+++ /oup/structdefs/06-04-19/TxtC.txt	(revision 8)
@@ -0,0 +1,5 @@
+Text Console
+File id	$00	12	File id
+Level id	$04	17	Level id
+IGPA-link	$08	12	Link to the In-Game User Interface Page Array
+Not used	$0C	1020	Not used
Index: /oup/structdefs/06-04-19/VCRA.txt
===================================================================
--- /oup/structdefs/06-04-19/VCRA.txt	(revision 8)
+++ /oup/structdefs/06-04-19/VCRA.txt	(revision 8)
@@ -0,0 +1,9 @@
+3D Vector Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1018	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	12
+x-coordinate	$00	9	x-coordinate of the vector
+y-coordinate	$04	9	y-coordinate (height) of the vector
+z-coordinate	$08	9	z-coordinate of the vector
Index: /oup/structdefs/06-04-19/WMCL.txt
===================================================================
--- /oup/structdefs/06-04-19/WMCL.txt	(revision 8)
+++ /oup/structdefs/06-04-19/WMCL.txt	(revision 8)
@@ -0,0 +1,8 @@
+WM (Window Menu) Cursor List
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	8
+Unknown	$00	4	Unknown; do not change it, Oni won't start if you do that
+PSpc-link	$04	12	Link to the Part Specification
Index: /oup/structdefs/06-04-19/WMDD.txt
===================================================================
--- /oup/structdefs/06-04-19/WMDD.txt	(revision 8)
+++ /oup/structdefs/06-04-19/WMDD.txt	(revision 8)
@@ -0,0 +1,33 @@
+Window Menu Dialog Data
+File id	$00	12	File id
+Level id	$04	4	Level id
+Window title	$08	10256	Title of the main-window
+Window id	$108	4	Id of the main-window
+Window status	$10C	4	Status of the main-window
+Window design	$110	2	Design of the main-window
+Window position	$112	6	Position of the main-window
+Unknown	$114	4	Unknown; always the same
+Width	$118	2	x-dimension of the main-window
+Height	$11A	2	y-dimension of the main-window
+Packages	$11C	4	Amount of packages that follow
+
+*Package		$120	$11C	4	292
+Caption	$0	10256	Caption of the sub-window
+Type	$100	2	Type
+Target id	$102	2	Id of the target
+Option	$104	2	Option
+Unknown	$106	2	Unknown
+Window design	$108	2	Design of the sub-window
+Visible option	$10A	2	Visible option of the sub-window
+x-position	$10C	2	x-position of the sub-window (from the upper left corner of the main-window)
+y-position	$10E	2	y-position of the sub-window (from the upper left corner of the main-window)
+Width	$110	2	x-dimension of the sub-window
+Height	$112	2	y-dimension of the sub-window
+TSFF-link	$114	12	Link to the Font Family
+Font option	$118	4	Font option
+Font color B	$11C	1	Font color - blue part
+Font color G	$11D	1	Font color - green part
+Font color R	$11E	1	Font color - red part
+Unknown	$11F	1	Unknown
+Unknown	$120	2	Unknown; always the same
+Font size	$122	2	Font size
Index: /oup/structdefs/06-04-19/WMMB.txt
===================================================================
--- /oup/structdefs/06-04-19/WMMB.txt	(revision 8)
+++ /oup/structdefs/06-04-19/WMMB.txt	(revision 8)
@@ -0,0 +1,9 @@
+WM (Window Menu) Menu Bar
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1018	Not used
+Unknown	$1A	2	Unknown
+Packages	$1C	4	Amount of packages that follow
+
+*Package		$20	$1C	4	4
+WMM_-link	$00	12	Link to the Window Menu
Index: /oup/structdefs/06-04-19/WMM_.txt
===================================================================
--- /oup/structdefs/06-04-19/WMM_.txt	(revision 8)
+++ /oup/structdefs/06-04-19/WMM_.txt	(revision 8)
@@ -0,0 +1,12 @@
+WM (Window Menu) Menu
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1018	Not used
+Unknown	$1A	2	Unknown
+Menu name	$1C	10064	Name of the menu
+Packages	$5C	4	Amount of packages that follow
+
+*Package		$60	$5C	4	68
+Menu type	$00	2	Type of the menu
+Return number	$02	2	Number that returns if you choose this menu point
+Menu entry	$04	10064	Entry of the menu
Index: /oup/structdefs/06-04-19/WPge.txt
===================================================================
--- /oup/structdefs/06-04-19/WPge.txt	(revision 8)
+++ /oup/structdefs/06-04-19/WPge.txt	(revision 8)
@@ -0,0 +1,6 @@
+Weapon Page
+File id	$00	12	File id
+Level id	$04	17	Level id
+ONWC-link	$08	12	Link to the Oni Weapon Class
+IGPG-link	$0C	12	Link to the In-Game User Interface Page
+Not used	$10	1016	Not used
Index: /oup/structdefs/06-04-24/ABNA.txt
===================================================================
--- /oup/structdefs/06-04-24/ABNA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ABNA.txt	(revision 8)
@@ -0,0 +1,11 @@
+BSP Tree Node Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	16
+Unknown	$00	4	Unknown
+Unknown	$04	3	Unknown
+High bit	$07	1	High bit
+Unknown	$08	4	Unknown
+Unknown	$0C	4	Unknown
Index: /oup/structdefs/06-04-24/AGDB.txt
===================================================================
--- /oup/structdefs/06-04-24/AGDB.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AGDB.txt	(revision 8)
@@ -0,0 +1,8 @@
+Gunk Quad Debug Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	16
+Unknown	$00	11	Unknown
+Unknown	$04	11	Unknown
Index: /oup/structdefs/06-04-24/AGQC.txt
===================================================================
--- /oup/structdefs/06-04-24/AGQC.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AGQC.txt	(revision 8)
@@ -0,0 +1,14 @@
+Gunk Quad Collision Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	28
+Unknown	$00	3	Unknown
+High bit	$03	1	High bit
+Unknown	$04	9	Unknown
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
Index: /oup/structdefs/06-04-24/AGQG.txt
===================================================================
--- /oup/structdefs/06-04-24/AGQG.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AGQG.txt	(revision 8)
@@ -0,0 +1,25 @@
+Gunk Quad General Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	56
+Unknown	$00	4	Unknown
+Unknown	$04	4	Unknown
+Unknown	$08	4	Unknown
+Unknown	$0C	4	Unknown
+Unknown	$10	4	Unknown
+Unknown	$14	4	Unknown
+Unknown	$18	4	Unknown
+Unknown	$1C	4	Unknown
+Unknown	$20	2	Unknown
+Unknown	$22	2	Unknown
+Unknown	$24	2	Unknown
+Unknown	$26	2	Unknown
+Unknown	$28	2	Unknown
+Unknown	$2A	2	Unknown
+Unknown	$2C	2	Unknown
+Unknown	$2E	2	Unknown
+Unknown	$30	2	Unknown
+Unknown	$32	2	Unknown
+Unknown	$34	4	Unknown
Index: /oup/structdefs/06-04-24/AGQR.txt
===================================================================
--- /oup/structdefs/06-04-24/AGQR.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AGQR.txt	(revision 8)
@@ -0,0 +1,8 @@
+Gunk Quad Render Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+Unknown	$00	2	Unknown
+Not used	$02	1002	Not used
Index: /oup/structdefs/06-04-24/AISA.txt
===================================================================
--- /oup/structdefs/06-04-24/AISA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AISA.txt	(revision 8)
@@ -0,0 +1,27 @@
+AI Character Setup Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	352
+Unknown	$00	10032	unknown; always zero; maybe space for notes
+Charcter id	$20	2	Id of the character, which you can spawn with the script command "chr_create"
+Flag id	$22	2	Od of the flag, where Oni spawns the character (works only, if the flag exits; look to Flag.BINA for a flag list)
+Unknown	$24	2	Unknown
+Unknown	$26	2	Unknown
+ONCC-link	$28	12	Link to the Character Class
+Unknown	$2C	4	Unknown; always the same
+Unknown	$30	10032	Unknown; never used in Oni
+Spawn function	$50	10032	Name of the function, which is called up when Oni spawns the character
+Lose function	$70	10032	Name of the function, which is called up when the character dies
+Alert function	$90	10032	Name of the function, which is called up when the character notices the player
+Unknown	$B0	10032	Unknown; never used in Oni
+Hit function	$D0	10032	Name of the function, which is called up when someone hits the character the first time
+Health = 1 function	$F0	10032	Name of the function, which is called up when the health of the character is equal 1
+Reload function	$110	10032	Name of the function, which is called up when the character reloads its weapon with its last ammo/cell; works only, if the character has some ammo/cells when Oni spawns it
+Unknown	$130	10032	Unknown; never used in Oni
+ONWC-link	$150	12	Link to the Weapon Class; used to give the charcater a weapon
+Unknown	$154	2	Unknown
+Unknown	$156	14	Unknown; always the same
+Unknown	$158	4	Unknown; always the same
+Unknown	$15C	4	Unknown; always the same
Index: /oup/structdefs/06-04-24/AITR.txt
===================================================================
--- /oup/structdefs/06-04-24/AITR.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AITR.txt	(revision 8)
@@ -0,0 +1,15 @@
+AI Script Trigger Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	84
+Unknown	$00	2	Unknown
+Unknown	$02	2	Unknown
+Unknown	$04	2	Unknown
+Unknown	$06	2	Unknown
+Unknown	$08	2	Unknown
+Unknown	$0A	2	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	10064	Unknown
Index: /oup/structdefs/06-04-24/AKAA.txt
===================================================================
--- /oup/structdefs/06-04-24/AKAA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AKAA.txt	(revision 8)
@@ -0,0 +1,9 @@
+Adjacency Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	12
+Unknown	$00	4	Unknown
+Unknown	$04	4	Unknown
+Unknown	$08	4	Unknown
Index: /oup/structdefs/06-04-24/AKBA.txt
===================================================================
--- /oup/structdefs/06-04-24/AKBA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AKBA.txt	(revision 8)
@@ -0,0 +1,14 @@
+Side Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	28
+Unknown	$00	3	Unknown
+High bit	$03	1	High bit
+Unknown	$04	4	Unknown
+Unknown	$08	4	Unknown
+Unknown	$0C	4	Unknown
+Unknown	$10	4	Unknown
+Unknown	$14	4	Unknown
+Unknown	$18	4	Unknown
Index: /oup/structdefs/06-04-24/AKBP.txt
===================================================================
--- /oup/structdefs/06-04-24/AKBP.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AKBP.txt	(revision 8)
@@ -0,0 +1,10 @@
+BSP Node Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	12
+Unknown	$00	3	Unknown
+High bit	$03	1	High bit
+Unknown	$04	4	Unknown
+Unknown	$08	4	Unknown; always the same
Index: /oup/structdefs/06-04-24/AKDA.txt
===================================================================
--- /oup/structdefs/06-04-24/AKDA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AKDA.txt	(revision 8)
@@ -0,0 +1,19 @@
+Door Frame Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	52
+Unknown	$00	4	Unknown
+Low left x-coordinate	$04	9	x-coordinate of the lower left point of the doorframe
+Low left y-coordinate	$08	9	y-coordinate (height) of the lower left point of the doorframe
+Low left z-coordinate	$0C	9	z-coordinate of the lower left point of the doorframe
+Up right x-coordinate	$10	9	x-coordinate of the upper right point of the doorframe
+Up right y-coordinate	$14	9	y-coordinate (height) of the upper right point of the doorframe
+Up right z-coordinate	$18	9	z-coordinate of the upper right point of the doorframe
+Center x-coordinate	$1C	9	x-coordinate of the center point of the doorframe
+Center y-coordinate	$20	9	y-coordinate (height) of the center point of the doorframe
+Center z-coordinate	$24	9	z-coordinate of the center point of the doorframe
+Depth	$28	9	Depth of the doorframe
+Width	$2C	9	Width of the doorframe
+Height	$30	9	Height of the doorframe
Index: /oup/structdefs/06-04-24/AKEV.txt
===================================================================
--- /oup/structdefs/06-04-24/AKEV.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AKEV.txt	(revision 8)
@@ -0,0 +1,28 @@
+Environment
+File id	$00	12	File id
+Level id	$04	17	Level id
+PNTA-link	$08	12	Link to the 3D Point Array
+PLEA-link	$0C	12	Link to the Plane Equation Array
+TXCA-link	$10	12	Link to the Texture Coordinate Array
+AGQG-link	$14	12	Link to the Gunk Quad General Array
+AGQR-link	$18	12	Link to the Gunk Quad Render Array
+AGQC-link	$1C	12	Link to the Gunk Quad Collision Array
+AGDB-link	$20	12	Link to the Gunk Quad Debug Array
+TXMA-link	$24	12	Link to the Texture Map Array
+AKVA-link	$28	12	Link to the BNV Node Array
+AKBA-link	$2C	12	Link to the Side Array
+IDXA-link	$30	12	Link to the Index Array
+IDXA-link	$34	12	Link to the Index Array
+AKBP-link	$38	12	Link to the BSP Node Array
+ABNA-link	$3C	12	Link to the BSP Tree Node Array
+AKOT-link	$40	12	Link to the Oct Tree
+AKAA-link	$44	12	Link to the Adjacency Array
+AKDA-link	$48	12	Link to the Door Frame Array
+Neg. x-coordinate	$4C	9	Maximal negative x-coordinate of the level model
+Neg. y-coordinate	$50	9	Maximal negative y-coordinate of the level model
+Neg. z-coordinate	$54	9	Maximal negative z-coordinate (height) of the level model
+Pos. x-coordinate	$58	9	Maximal positive x-coordinate of the level model
+Pos. y-coordinate	$5C	9	Maximal positive y-coordinate (height) of the level model
+Pos. z-coordinate	$60	9	Maximal positive z-coordinate of the level model
+Not used	$64	1024	Not used
+Unknown	$7C	9	Unknown; maybe the tolerance
Index: /oup/structdefs/06-04-24/AKOT.txt
===================================================================
--- /oup/structdefs/06-04-24/AKOT.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AKOT.txt	(revision 8)
@@ -0,0 +1,9 @@
+Oct Tree
+File id	$00	12	File id
+Level id	$04	17	Level id
+OTIT-link	$08	12	Link to the Oct Tree Interior Node Array
+OTLF-link	$0C	12	Link to the Oct Tree Leaf Node Array
+QTNA-link	$10	12	Link to the Quad Tree Node Array
+IDXA-link	$14	12	Link to the Index Array
+IDXA-link	$18	12	Link to the Index Array
+Not used	$1C	1004	Not used
Index: /oup/structdefs/06-04-24/AKVA.txt
===================================================================
--- /oup/structdefs/06-04-24/AKVA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/AKVA.txt	(revision 8)
@@ -0,0 +1,35 @@
+BNV Node Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	116
+Unknown	$00	4	Unknown
+Id	$04	4	Id
+Unknown	$08	4	Unknown
+Unknown	$0C	4	Unknown
+Unknown	$10	4	Unknown
+Unknown	$14	4	Unknown
+Unknown	$18	4	Unknown
+Unknown	$1C	4	Unknown
+Unknown	$20	4	Unknown
+Unknown	$24	11	From this position starts the unknown part in the raw file
+Size	$28	4	Size of the part in the raw file
+Unknown	$2C	9	Unknown
+Unknown	$30	9	Unknown
+Unknown	$34	9	Unknown
+Unknown	$38	9	Unknown
+Unknown	$3C	9	Unknown
+Unknown	$40	9	Unknown
+Unknown	$44	9	Unknown
+Unknown	$48	4	Unknown
+Id (again)	$4C	4	Id (again)
+Unknown	$50	9	Unknown
+Unknown	$54	9	Unknown
+Unknown	$58	9	Unknown
+Unknown	$5C	4	Unknown
+Unknown	$60	9	Unknown
+Unknown	$64	9	Unknown
+Unknown	$68	9	Unknown
+Unknown	$6C	9	Unknown
+Unknown	$70	9	Unknown
Index: /oup/structdefs/06-04-24/BINA.txt
===================================================================
--- /oup/structdefs/06-04-24/BINA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/BINA.txt	(revision 8)
@@ -0,0 +1,6 @@
+Binary Data
+File id	$00	12	File id
+Level id	$04	17	Level id
+Size	$08	4	Size of the part in the raw file
+Offset	$0C	11	At this position starts the part in the raw/sep file
+Not used	$10	1016	Not used
Index: /oup/structdefs/06-04-24/CBPI.txt
===================================================================
--- /oup/structdefs/06-04-24/CBPI.txt	(revision 8)
+++ /oup/structdefs/06-04-24/CBPI.txt	(revision 8)
@@ -0,0 +1,61 @@
+Character Body Part Impacts
+File id	$00	12	File id
+Level id	$04	17	Level id
+Impt-link	$08	12	Link to the Impact Tree
+Impt-link	$0C	12	Link to the Impact Tree
+Impt-link	$10	12	Link to the Impact Tree
+Impt-link	$14	12	Link to the Impact Tree
+Impt-link	$18	12	Link to the Impact Tree
+Impt-link	$1C	12	Link to the Impact Tree
+Impt-link	$20	12	Link to the Impact Tree
+Impt-link	$24	12	Link to the Impact Tree
+Impt-link	$28	12	Link to the Impact Tree
+Impt-link	$2C	12	Link to the Impact Tree
+Impt-link	$30	12	Link to the Impact Tree
+Impt-link	$34	12	Link to the Impact Tree
+Impt-link	$38	12	Link to the Impact Tree
+Impt-link	$3C	12	Link to the Impact Tree
+Impt-link	$40	12	Link to the Impact Tree
+Impt-link	$44	12	Link to the Impact Tree
+Impt-link	$48	12	Link to the Impact Tree
+Impt-link	$4C	12	Link to the Impact Tree
+Impt-link	$50	12	Link to the Impact Tree
+Impt-link	$54	12	Link to the Impact Tree
+Impt-link	$58	12	Link to the Impact Tree
+Impt-link	$5C	12	Link to the Impact Tree
+Impt-link	$60	12	Link to the Impact Tree
+Impt-link	$64	12	Link to the Impact Tree
+Impt-link	$68	12	Link to the Impact Tree
+Impt-link	$6C	12	Link to the Impact Tree
+Impt-link	$70	12	Link to the Impact Tree
+Impt-link	$74	12	Link to the Impact Tree
+Impt-link	$78	12	Link to the Impact Tree
+Impt-link	$7C	12	Link to the Impact Tree
+Impt-link	$80	12	Link to the Impact Tree
+Impt-link	$84	12	Link to the Impact Tree
+Impt-link	$88	12	Link to the Impact Tree
+Impt-link	$8C	12	Link to the Impact Tree
+Impt-link	$90	12	Link to the Impact Tree
+Impt-link	$94	12	Link to the Impact Tree
+Impt-link	$98	12	Link to the Impact Tree
+Impt-link	$9C	12	Link to the Impact Tree
+Impt-link	$A0	12	Link to the Impact Tree
+Impt-link	$A4	12	Link to the Impact Tree
+Impt-link	$A8	12	Link to the Impact Tree
+Impt-link	$AC	12	Link to the Impact Tree
+Impt-link	$B0	12	Link to the Impact Tree
+Impt-link	$B4	12	Link to the Impact Tree
+Impt-link	$B8	12	Link to the Impact Tree
+Impt-link	$BC	12	Link to the Impact Tree
+Impt-link	$C0	12	Link to the Impact Tree
+Impt-link	$C4	12	Link to the Impact Tree
+Impt-link	$C8	12	Link to the Impact Tree
+Impt-link	$CC	12	Link to the Impact Tree
+Impt-link	$D0	12	Link to the Impact Tree
+Impt-link	$D4	12	Link to the Impact Tree
+Impt-link	$D8	12	Link to the Impact Tree
+Impt-link	$DC	12	Link to the Impact Tree
+Impt-link	$E0	12	Link to the Impact Tree
+Impt-link	$E4	12	Link to the Impact Tree
+Impt-link	$E8	12	Link to the Impact Tree
+Not used	$EC	1020	Not used
Index: /oup/structdefs/06-04-24/CBPM.txt
===================================================================
--- /oup/structdefs/06-04-24/CBPM.txt	(revision 8)
+++ /oup/structdefs/06-04-24/CBPM.txt	(revision 8)
@@ -0,0 +1,23 @@
+Character Body Part Material
+File id	$00	12	File id
+Level id	$04	17	Level id
+Mtrl-link	$08	12	Link to the Material
+Mtrl-link	$0C	12	Link to the Material
+Mtrl-link	$10	12	Link to the Material
+Mtrl-link	$14	12	Link to the Material
+Mtrl-link	$18	12	Link to the Material
+Mtrl-link	$1C	12	Link to the Material
+Mtrl-link	$20	12	Link to the Material
+Mtrl-link	$24	12	Link to the Material
+Mtrl-link	$28	12	Link to the Material
+Mtrl-link	$2C	12	Link to the Material
+Mtrl-link	$30	12	Link to the Material
+Mtrl-link	$34	12	Link to the Material
+Mtrl-link	$38	12	Link to the Material
+Mtrl-link	$3C	12	Link to the Material
+Mtrl-link	$40	12	Link to the Material
+Mtrl-link	$44	12	Link to the Material
+Mtrl-link	$48	12	Link to the Material
+Mtrl-link	$4C	12	Link to the Material
+Mtrl-link	$50	12	Link to the Material
+Not used	$54	1012	Not used
Index: /oup/structdefs/06-04-24/CONS.txt
===================================================================
--- /oup/structdefs/06-04-24/CONS.txt	(revision 8)
+++ /oup/structdefs/06-04-24/CONS.txt	(revision 8)
@@ -0,0 +1,18 @@
+Console
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	4	Unknown; always the same
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown; always the same
+Unknown	$14	9	Unknown; always the same
+Unknown	$18	9	Unknown
+Unknown	$1C	9	Unknown; always the same
+Unknown	$20	9	Unknown; always the same
+OFGA-link	$24	12	Link to the Object Furn Geom Array
+M3GM-link	$28	12	Link to the Geometry
+Unknown	$2C	2	Unknown; always the same
+Unknown	$2E	2	Unknown; always the same
+Unknown	$30	10032	Unknown; always the same
+Unknown	$50	10032	Unknown; always the same
+Unknown	$70	10032	Unknown; always the same
+Not used	$90	1016	Not used
Index: /oup/structdefs/06-04-24/CRSA.txt
===================================================================
--- /oup/structdefs/06-04-24/CRSA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/CRSA.txt	(revision 8)
@@ -0,0 +1,244 @@
+Corpse Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1012	Not used
+Packages available	$14	4	Amount of packages that are available
+Packages used	$18	4	Amount of packages that follow
+Packages possible	$1C	4	Amount of packages that are possible
+*Package		$20	$18	4	1100
+Old file name	$00	10160	Old file name
+ONCC-link	$A0	12	Link to the Character Class
+1st point x-coordinate	$A4	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$A8	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$AC	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$B0	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$B4	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$B8	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$BC	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$C0	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$C4	9	z-position of the 3rd point of an equilateral triangle
+Pelvis x-position	$C8	9	x-position of the pelvis
+Pelvis y-position	$CC	9	y-position (height) of the pelvis
+Pelvis z-position	$D0	9	z-position of the pelvis
+1st point x-coordinate	$D4	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$D8	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$DC	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$E0	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$E4	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$E8	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$EC	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$F0	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$F4	9	z-position of the 3rd point of an equilateral triangle
+Left thigh x-position	$F8	9	x-position of the left thigh
+Left thigh y-position	$FC	9	y-position (height) of the left thigh
+Left thigh z-position	$100	9	z-position of the left thigh
+1st point x-coordinate	$104	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$108	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$10C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$110	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$114	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$118	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$11C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$120	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$124	9	z-position of the 3rd point of an equilateral triangle
+Left calf x-position	$128	9	x-position of the left calf
+Left calf y-position	$12C	9	y-position (height) of the left calf
+Left calf z-position	$130	9	z-position of the left calf
+1st point x-coordinate	$134	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$138	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$13C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$140	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$144	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$148	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$14C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$150	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$154	9	z-position of the 3rd point of an equilateral triangle
+Left foot x-position	$158	9	x-position of the left foot
+Left foot y-position	$15C	9	y-position (height) of the left foot
+Left foot z-position	$160	9	z-position of the left foot
+1st point x-coordinate	$164	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$168	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$16C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$170	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$174	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$178	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$17C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$180	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$184	9	z-position of the 3rd point of an equilateral triangle
+Right thigh x-position	$188	9	x-position of the right thigh
+Right thigh y-position	$18C	9	y-position (height) of the right thigh
+Right thigh z-position	$190	9	z-position of the right thigh
+1st point x-coordinate	$194	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$198	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$19C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$1A0	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$1A4	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$1A8	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$1AC	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$1B0	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$1B4	9	z-position of the 3rd point of an equilateral triangle
+Right calf x-position	$1B8	9	x-position of the right calf
+Right calf y-position	$1BC	9	y-position (height) of the right calf
+Right calf z-position	$1C0	9	z-position of the right calf
+1st point x-coordinate	$1C4	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$1C8	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$1CC	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$1D0	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$1D4	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$1D8	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$1DC	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$1E0	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$1E4	9	z-position of the 3rd point of an equilateral triangle
+Right foot x-position	$1E8	9	x-position of the right foot
+Right foot y-position	$1EC	9	y-position (height) of the right foot
+Right foot z-position	$1F0	9	z-position of the right foot
+1st point x-coordinate	$1F4	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$1F8	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$1FC	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$200	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$204	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$208	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$20C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$210	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$214	9	z-position of the 3rd point of an equilateral triangle
+Mid x-position	$218	9	x-position of the mid
+Mid y-position	$21C	9	y-position (height) of the mid
+Mid z-position	$220	9	z-position of the mid
+1st point x-coordinate	$224	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$228	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$22C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$230	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$234	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$238	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$23C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$240	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$244	9	z-position of the 3rd point of an equilateral triangle
+Chest x-position	$248	9	x-position of the chest
+Chest y-position	$24C	9	y-position (height) of the chest
+Chest z-position	$250	9	z-position of the chest
+1st point x-coordinate	$254	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$258	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$25C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$260	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$264	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$268	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$26C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$270	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$274	9	z-position of the 3rd point of an equilateral triangle
+Neck x-position	$278	9	x-position of the neck
+Neck y-position	$27C	9	y-position (height) of the neck
+Neck z-position	$280	9	z-position of the neck
+1st point x-coordinate	$284	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$288	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$28C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$290	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$294	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$298	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$29C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$2A0	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$2A4	9	z-position of the 3rd point of an equilateral triangle
+Head x-position	$2A8	9	x-position of the head
+Head y-position	$2AC	9	y-position (height) of the head
+Head z-position	$2B0	9	z-position of the head
+1st point x-coordinate	$2B4	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$2B8	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$2BC	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$2C0	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$2C4	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$2C8	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$2CC	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$2D0	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$2D4	9	z-position of the 3rd point of an equilateral triangle
+Left shoulder x-position	$2D8	9	x-position of the left shoulder
+Left shoulder y-position	$2DC	9	y-position (height) of the left shoulder
+Left shoulder z-position	$2E0	9	z-position of the left shoulder
+1st point x-coordinate	$2E4	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$2E8	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$2EC	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$2F0	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$2F4	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$2F8	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$2FC	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$300	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$304	9	z-position of the 3rd point of an equilateral triangle
+Left bicep x-position	$308	9	x-position of the left bicep
+Left bicep y-position	$30C	9	y-position (height) of the left bicep
+Left bicep z-position	$310	9	z-position of the left bicep
+1st point x-coordinate	$314	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$318	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$31C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$320	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$324	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$328	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$32C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$330	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$334	9	z-position of the 3rd point of an equilateral triangle
+Left wrist x-position	$338	9	x-position of the left wrist
+Left wrist y-position	$33C	9	y-position (height) of the left wrist
+Left wrist z-position	$340	9	z-position of the left wrist
+1st point x-coordinate	$344	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$348	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$34C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$350	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$354	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$358	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$35C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$360	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$364	9	z-position of the 3rd point of an equilateral triangle
+Left hand x-position	$368	9	x-position of the left hand
+Left hand y-position	$36C	9	y-position (height) of the left hand
+Left hand z-position	$370	9	z-position of the left hand
+1st point x-coordinate	$374	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$378	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$37C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$380	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$384	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$388	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$38C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$390	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$394	9	z-position of the 3rd point of an equilateral triangle
+Right shoulder x-position	$398	9	x-position of the right shoulder
+Right shoulder y-position	$39C	9	y-position (height) of the right shoulder
+Right shoulder z-position	$3A0	9	z-position of the right shoulder
+1st point x-coordinate	$3A4	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$3A8	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$3AC	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$3B0	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$3B4	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$3B8	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$3BC	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$3C0	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$3C4	9	z-position of the 3rd point of an equilateral triangle
+Right bicep x-position	$3C8	9	x-position of the right bicep
+Right bicep y-position	$3CC	9	y-position (height) of the right bicep
+Right bicep z-position	$3D0	9	z-position of the right bicep
+1st point x-coordinate	$3D4	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$3D8	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$3DC	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$3E0	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$3E4	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$3E8	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$3EC	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$3F0	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$3F4	9	z-position of the 3rd point of an equilateral triangle
+Right wrist x-position	$3F8	9	x-position of the right wrist
+Right wrist y-position	$3FC	9	y-position (height) of the right wrist
+Right wrist z-position	$400	9	z-position of the right wrist
+1st point x-coordinate	$404	9	x-position of the 1st point of an equilateral triangle
+1st point y-coordinate	$408	9	y-position (height) of the 1st point of an equilateral triangle
+1st point z-coordinate	$40C	9	z-position of the 1st point of an equilateral triangle
+2nd point x-coordinate	$410	9	x-position of the 2nd point of an equilateral triangle
+2nd point y-coordinate	$414	9	y-position (height) of the 2nd point of an equilateral triangle
+2nd point z-coordinate	$418	9	z-position of the 2nd point of an equilateral triangle
+3rd point x-coordinate	$41C	9	x-position of the 3rd point of an equilateral triangle
+3rd point y-coordinate	$420	9	y-position (height) of the 3rd point of an equilateral triangle
+3rd point z-coordinate	$424	9	z-position of the 3rd point of an equilateral triangle
+Right hand x-position	$428	9	x-position of the right hand
+Right hand y-position	$42C	9	y-position (height) of the right hand
+Right hand z-position	$430	9	z-position of the right hand
+Minimal x-coordinate	$434	9	Minimal x-coordinate of the bounding box
+Minimal y-coordinate	$438	9	Minimal y-coordinate (height) of the bounding box
+Minimal z-coordinate	$43C	9	Minimal z-coordinate of the bounding box
+Maximal x-coordinate	$440	9	Maximal x-coordinate of the bounding box
+Maximal y-coordinate	$444	9	Maximal y-coordinate (height) of the bounding box
+Maximal z-coordinate	$448	9	Maximal z-coordinate of the bounding box
Index: /oup/structdefs/06-04-24/DOOR.txt
===================================================================
--- /oup/structdefs/06-04-24/DOOR.txt	(revision 8)
+++ /oup/structdefs/06-04-24/DOOR.txt	(revision 8)
@@ -0,0 +1,15 @@
+DOOR File
+File id	$00	12	File id
+Level id	$04	17	Level id
+OFGA-link	$08	12	Link to the Object Furn Geom Array
+Unknown	$0C	4	Unknown; maybe a canceled link; always the same
+OBAN-link	$10	12	Link to the Object Animation
+Unknown	$14	9	Unknown; always the same
+Unknown	$18	4	Unknown; always the same
+Unknown	$1C	16	Unknown; always the same
+Unknown	$20	9	Unknown; always the same
+Door open sound	$24	132	Reference to an OSBD file of level 0
+Door close sound	$44	132	Reference to an OSBD file of level 0
+Unknown	$64	4	Unknown
+Unknown	$68	4	Unknown
+Not useed	$6C	1020	Not used
Index: /oup/structdefs/06-04-24/DPge.txt
===================================================================
--- /oup/structdefs/06-04-24/DPge.txt	(revision 8)
+++ /oup/structdefs/06-04-24/DPge.txt	(revision 8)
@@ -0,0 +1,8 @@
+Diary Page
+File id	$00	12	File id
+Level id	$04	17	Level id
+Level	$08	2	Level
+Page	$0A	2	Page
+Not used	$0C	1052	Not used
+IGPG-link	$40	12	Link to the In-Game User Interface Page
+Not used	$44	1028	Not used
Index: /oup/structdefs/06-04-24/ENVP.txt
===================================================================
--- /oup/structdefs/06-04-24/ENVP.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ENVP.txt	(revision 8)
@@ -0,0 +1,23 @@
+Environment Particle Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	208
+3D particle	$00	164	Reference to a BINA file of level 0
+Particle name	$40	10048	Name of the particle
+Unknown	$70	9	Unknown
+Unknown	$74	9	Unknown
+Unknown	$78	9	Unknown
+Unknown	$7C	9	Unknown
+Unknown	$80	9	Unknown
+Unknown	$84	9	Unknown
+Unknown	$88	9	Unknown
+Unknown	$8C	9	Unknown
+Unknown	$90	9	Unknown
+Unknown	$94	9	Unknown
+Unknown	$98	9	Unknown
+Unknown	$9C	9	Unknown
+Unknown	$A0	9	Unknown
+Unknown	$A4	9	Unknown
+Unknown	$A8	1040	Unknown; always the same
Index: /oup/structdefs/06-04-24/FILM.txt
===================================================================
--- /oup/structdefs/06-04-24/FILM.txt	(revision 8)
+++ /oup/structdefs/06-04-24/FILM.txt	(revision 8)
@@ -0,0 +1,25 @@
+Film
+File id	$00	12	File id
+Level id	$04	17	Level id
+x-coordinate	$08	9	x-coordinate of the start point
+y-coordinate	$0C	9	y-coordinate (height) of the start point
+z-coordinate	$10	9	z-coordinate of the start point
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
+Look left/right	$1C	9	Look from left or right to facing state
+Look up/down	$20	9	Look up or down
+Film lenght	$24	4	Lenght of the film in 1/60 seconds
+Unknown	$28	4	Unknown
+Unknown	$2C	4	Unknown
+Not used	$30	1012	Not used
+Packages	$3C	4	Amount of packages that follow
+*Package		$40	$3C	4	24
+Camera angle	$00	9	Camera angle in degrees (up / down)
+Character rotation	$04	9	Rotation of the charcter on the y-axis in degrees
+Unknown	$08	2	Unknown
+Movement	$0A	10	Movement bitset
+Unknown	$0B	1	Unknown
+Unknown	$0C	4	Unknown
+Frames to go	$10	4	Number of the frames to go
+Unknown	$14	2	Unknown
+Unknown	$16	2	Unknown
Index: /oup/structdefs/06-04-24/HPge.txt
===================================================================
--- /oup/structdefs/06-04-24/HPge.txt	(revision 8)
+++ /oup/structdefs/06-04-24/HPge.txt	(revision 8)
@@ -0,0 +1,6 @@
+Help Page
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1004	Not used
+IGPG-link	$0C	12	Link to the In-Game User Interface Page
+Not used	$10	1016	Not used
Index: /oup/structdefs/06-04-24/IDXA.txt
===================================================================
--- /oup/structdefs/06-04-24/IDXA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/IDXA.txt	(revision 8)
@@ -0,0 +1,8 @@
+Index Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+Index id	$00	3	Index id
+High bit	$03	1	High bit
Index: /oup/structdefs/06-04-24/IGHH.txt
===================================================================
--- /oup/structdefs/06-04-24/IGHH.txt	(revision 8)
+++ /oup/structdefs/06-04-24/IGHH.txt	(revision 8)
@@ -0,0 +1,15 @@
+IGUI (In-Game User Interface) HUD (Head-Up Display) Help
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1028	Not used
+TXMP-link	$24	12	Link to the left HUD image
+TXMP-link	$28	12	Link to the right HUD image
+Left image position	$2C	4	The left HUD image starts 55 pixel from the left screen border
+Right image position	$30	4	The right HUD image starts 42 pixel from the right screen border (65535 - 65493 = 42)
+Left words	$34	4	Number of words on the left side
+Right words	$38	4	Number of words on the right side
+Word-packages	$3C	4	Amount of word-packages that follow
+*Package		$40	$3C	4	68
+Text field	$00	10064	Text field (all entries after the fist 00 are useless)
+Text x-position	$40	2	x-position of the text (from the left/right border of the HUD image)
+Text y-position	$42	2	y-position of the text (from the top border of the HUD image)
Index: /oup/structdefs/06-04-24/IGPA.txt
===================================================================
--- /oup/structdefs/06-04-24/IGPA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/IGPA.txt	(revision 8)
@@ -0,0 +1,7 @@
+IGUI (In-Game User Interface) Page Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+IGPG-link	$00	12	Link to the In-Game User Interface Page
Index: /oup/structdefs/06-04-24/IGPG.txt
===================================================================
--- /oup/structdefs/06-04-24/IGPG.txt	(revision 8)
+++ /oup/structdefs/06-04-24/IGPG.txt	(revision 8)
@@ -0,0 +1,15 @@
+IGUI (In-Game User Interface) Page
+File id	$00	12	File id
+Level id	$04	17	Level id
+TSFF-link	$08	12	Link to the Font Family
+Font option	$0C	4	Font option
+Font color B	$10	1	Font color - blue part
+Font color G	$11	1	Font color - green part
+Font color R	$12	1	Font color - red part
+Unknown	$13	1	Unknown
+Font size	$14	2	Font size of the text; maybe the minimal font size in connection to the screen resolution
+Enabler	$16	2	Enables the previous entries; it's a bitset
+PSpc-link	$18	12	Link to the Part Specification
+IGSA-link	$1C	12	Link to the In-Game User Interface String Array
+IGSA-link	$20	12	Link to the In-Game User Interface String Array
+Not used	$24	1028	Not used
Index: /oup/structdefs/06-04-24/IGSA.txt
===================================================================
--- /oup/structdefs/06-04-24/IGSA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/IGSA.txt	(revision 8)
@@ -0,0 +1,7 @@
+IGUI (In-Game User Interface) String Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+IGSt-link	$00	12	Link to the In-Game User Interface String
Index: /oup/structdefs/06-04-24/IGSt.txt
===================================================================
--- /oup/structdefs/06-04-24/IGSt.txt	(revision 8)
+++ /oup/structdefs/06-04-24/IGSt.txt	(revision 8)
@@ -0,0 +1,13 @@
+IGUI (In-Game User Interface) String
+File id	$00	12	File id
+Level id	$04	17	Level id
+TSFF-link	$08	12	Link to the Font Family
+Font option	$0C	4	Font option
+Font color B	$10	1	Font color - blue part
+Font color G	$11	1	Font color - green part
+Font color R	$12	1	Font color - red part
+Unknown	$13	1	Unknown
+Font size	$14	2	Font size of the text
+Enabler	$16	2	Enables the previous entries; it's a bitset
+Text	$18	10384	Space for text
+Not used	$198	1008	Not used
Index: /oup/structdefs/06-04-24/IPge.txt
===================================================================
--- /oup/structdefs/06-04-24/IPge.txt	(revision 8)
+++ /oup/structdefs/06-04-24/IPge.txt	(revision 8)
@@ -0,0 +1,6 @@
+Item Page
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	4	Unknown
+Impt-link	$0C	12	Link to the In-Game User Interface Page
+Not used	$10	1016	Not used
Index: /oup/structdefs/06-04-24/Impt.txt
===================================================================
--- /oup/structdefs/06-04-24/Impt.txt	(revision 8)
+++ /oup/structdefs/06-04-24/Impt.txt	(revision 8)
@@ -0,0 +1,7 @@
+Impact Tree
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	14	Unknown
+Not used	$0A	1006	Not used
+Impt-link	$10	12	Link to the next higher Impact Tree
+Not used	$14	1012	Not used
Index: /oup/structdefs/06-04-24/KeyI.txt
===================================================================
--- /oup/structdefs/06-04-24/KeyI.txt	(revision 8)
+++ /oup/structdefs/06-04-24/KeyI.txt	(revision 8)
@@ -0,0 +1,14 @@
+Key Icons
+File id	$00	12	File id
+Level id	$04	17	Level id
+TXMP-link	$08	12	Link to the punch texture
+TXMP-link	$0C	12	Link to the kick texture
+TXMP-link	$10	12	Link to the forward texture
+TXMP-link	$14	12	Link to the backward texture
+TXMP-link	$18	12	Link to the left texture
+TXMP-link	$1C	12	Link to the right texture
+TXMP-link	$20	12	Link to the crouch texture
+TXMP-link	$24	12	Link to the jump texture
+TXMP-link	$28	12	Link to the hold texture
+TXMP-link	$2C	12	Link to the plus texture
+Not used	$30	1016	Not used
Index: /oup/structdefs/06-04-24/M3GA.txt
===================================================================
--- /oup/structdefs/06-04-24/M3GA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/M3GA.txt	(revision 8)
@@ -0,0 +1,7 @@
+Geometry Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+M3GM-link	$00	12	Link to the Geometry
Index: /oup/structdefs/06-04-24/M3GM.txt
===================================================================
--- /oup/structdefs/06-04-24/M3GM.txt	(revision 8)
+++ /oup/structdefs/06-04-24/M3GM.txt	(revision 8)
@@ -0,0 +1,13 @@
+Geometry
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	4	Unknown; not used
+PNTA-link	$0C	12	Link to the 3D Point Array
+VCRA-link	$10	12	Link to the 3D Vector Array
+VCRA-link	$14	12	Link to the 3D Vector Array
+TXCA-link	$18	12	Link to the Texture Coordinate Array
+IDXA-link	$1C	12	Link to the Index Array
+IDXA-link	$20	12	Link to the Index Array
+TXMP-link	$24	12	Link to the Texture
+Unknown	$28	4	Unknown; not used
+Not used	$2C	1020	Not used
Index: /oup/structdefs/06-04-24/Mtrl.txt
===================================================================
--- /oup/structdefs/06-04-24/Mtrl.txt	(revision 8)
+++ /oup/structdefs/06-04-24/Mtrl.txt	(revision 8)
@@ -0,0 +1,7 @@
+Material
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	14	Unknown
+Not used	$0A	1006	Not used
+Mtrl-link	$10	12	Link to the next higher Material
+Not used	$14	1012	Not used
Index: /oup/structdefs/06-04-24/OBAN.txt
===================================================================
--- /oup/structdefs/06-04-24/OBAN.txt	(revision 8)
+++ /oup/structdefs/06-04-24/OBAN.txt	(revision 8)
@@ -0,0 +1,44 @@
+Object Animation
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	4	Unknown
+Unknown	$0C	4	Unknown
+Unknown	$10	4	Unknown
+Unknown	$14	4	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	9	Unknown
+Unknown	$20	9	Unknown
+Unknown	$24	9	Unknown
+Unknown	$28	9	Unknown
+Unknown	$2C	9	Unknown
+Unknown	$30	9	Unknown
+Unknown	$34	9	Unknown
+Unknown	$38	9	Unknown
+x-position	$3C	9	x-position of the start point
+y-position	$40	9	y-position (height) of the start point
+z-position	$44	9	z-position of the start point
+Unknown	$48	9	Unknown
+Unknown	$4C	9	Unknown
+Unknown	$50	9	Unknown
+Unknown	$54	9	Unknown
+Unknown	$58	9	Unknown
+Unknown	$5C	9	Unknown
+Unknown	$60	9	Unknown
+Unknown	$64	9	Unknown
+Unknown	$68	9	Unknown
+Unknown	$6C	9	Unknown
+Unknown	$70	9	Unknown
+Unknown	$74	9	Unknown
+Frames	$78	2	Number of frames
+Animation time	$7A	2	Animation time in 1/60 seconds
+Unknown	$7C	2	Unknown
+Packages	$7E	2	Amount of packages that follow
+*Package		$80	$7E	2	32
+Unknown	$00	9	Unknown
+Unknown	$04	9	Unknown
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+x-position	$10	9	x-position
+y-position	$14	9	y-position
+z-position	$18	9	z-position
+Passed time	$1C	4	Passed time in 1/60 seconds
Index: /oup/structdefs/06-04-24/OBDC.txt
===================================================================
--- /oup/structdefs/06-04-24/OBDC.txt	(revision 8)
+++ /oup/structdefs/06-04-24/OBDC.txt	(revision 8)
@@ -0,0 +1,12 @@
+Door Class Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	24
+Unknown	$00	4	Unknown
+OBAN-link	$04	12	Link to the Object Animation
+Unknown	$08	4	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	4	Unknown
+Unknown	$14	4	Unknown
Index: /oup/structdefs/06-04-24/OBOA.txt
===================================================================
--- /oup/structdefs/06-04-24/OBOA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/OBOA.txt	(revision 8)
@@ -0,0 +1,36 @@
+Starting Object Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	240
+M3GA-link	$00	12	Link to the Geometry Array
+OBAN-link	$04	12	Link to the Object Animation
+ENVP-link	$08	12	Link to the Environment Particle Array
+Unknown	$0C	4	Unknown
+Unknown	$10	4	Unknown
+Unknown	$14	4	Unknown
+Unknown	$18	4	Unknown
+Unknown	$1C	4	Unknown
+Unknown	$20	9	Unknown
+Unknown	$24	9	Unknown
+Unknown	$28	9	Unknown
+Unknown	$2C	9	Unknown
+Unknown	$30	9	Unknown
+Unknown	$34	9	Unknown
+Unknown	$38	9	Unknown
+Unknown	$3C	9	Unknown
+Unknown	$40	9	Unknown
+Unknown	$44	9	Unknown
+Unknown	$48	9	Unknown
+Unknown	$4C	9	Unknown
+Unknown	$50	9	Unknown
+Unknown	$54	9	Unknown
+Unknown	$58	9	Unknown
+Unknown	$5C	9	Unknown
+Unknown	$60	9	Unknown
+Unknown	$64	9	Unknown
+Unknown	$68	9	Unknown
+Unknown	$6C	9	Unknown
+Name	$70	10064	Name of the object
+Unknown	$B0	10064	Unknown; maybe an old development relict
Index: /oup/structdefs/06-04-24/OFGA.txt
===================================================================
--- /oup/structdefs/06-04-24/OFGA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/OFGA.txt	(revision 8)
@@ -0,0 +1,10 @@
+Object Furniture Geometry Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	12
+Unknown	$00	2	Unknown
+Unknown	$02	2	Unknown
+M3GM-link	$04	12	Link to the Geometry
+Unknown	$08	4	Unknown
Index: /oup/structdefs/06-04-24/ONCC.txt
===================================================================
--- /oup/structdefs/06-04-24/ONCC.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONCC.txt	(revision 8)
@@ -0,0 +1,277 @@
+Oni character class
+File id	$00	12	File id
+Level id	$04	17	Level id
+TXMP-link	$28	12	Shadow texture
+Shadow height 5 	$2C	9	Height, where the shadow fades out completely
+Shadow height 4	$30	9	Height, where the diameter of the shadow decreases and the shadow fades out half
+Shadow height 3	$34	9	Height, where the diameter of the shadow decreases
+Shadow height 2	$38	9	Height, where the diameter of the shadow decreases
+Shadow height 1	$3C	9	Height, where the diameter of the shadow decreases
+Shadow option 1	$40	2	Transparency of the shadow for the first part of a jump
+Shadow option 2	$42	2	Transparency of the shadow for the second part of a jump
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use a hypo
+Hurt light sound	$98	132	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	132	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	132	Reference to an OSBD file of level 0
+Death sound	$F8	132	Reference to an OSBD file of level 0
+Rotation factor	$12C	9	Rotation factor * 360 degrees = possible rotation per frame or animation
+Taunt sound query	$2B0	1	0 = not used; 100 = used
+Alert sound query	$2B1	1	0 = not used; 100 = used
+Startle sound query	$2B2	1	0 = not used; 100 = used
+Check body sound query	$2B3	1	0 = not used; 100 = used
+Pursue sound query	$2B4	1	0 = not used; 100 = used
+Cower sound query	$2B5	1	0 = not used; 100 = used
+Punch heavy sound query	$2B6	1	0 = not used; 100 = used
+Kich heavy sound query	$2B7	1	0 = not used; 100 = used
+Super3 sound query	$2B8	1	0 = not used; 100 = used
+Super4 sound query	$2B9	1	0 = not used; 100 = used
+Taunt sound	$2BC	132	Reference to a SNDD file of level 0
+Alert sound	$2DC	132	Reference to a SNDD file of level 0
+Startle sound	$2FC	132	Reference to a SNDD file of level 0
+Check body sound	$31C	132	Reference to a SNDD file of level 0
+Pursue sound	$33C	132	Reference to a SNDD file of level 0
+Cower sound	$35C	132	Reference to a SNDD file of level 0
+Punch heavy sound	$37C	132	Reference to a SNDD file of level 0
+Kick heavy sound	$39C	132	Reference to a SNDD file of level 0
+Super3 sound	$3BC	132	Reference to a SNDD file of level 0
+Super4 sound	$3DC	132	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+ONCV-link	$434	12	Character varient link
+ONCP-link	$438	12	Character particle array link; useless?
+ONIA-link	$43C	12	Character impact array link; useless?
+Footstep walk impact	$454	230	Reference to an Impt file of level 0
+Footstep run impact	$4D6	230	Reference to an Impt file of level 0
+Footstep crouch impact	$558	230	Reference to an Impt file of level 0
+Fall slide impact	$5DA	230	Reference to an Impt file of level 0
+Fall land impact	$65C	230	Reference to an Impt file of level 0
+Fall land hard impact	$6DE	230	Reference to an Impt file of level 0
+Fall knockdown impact	$760	230	Reference to an Impt file of level 0
+Fall knockdown impact	$7E2	230	Reference to an Impt file of level 0
+Fall knockdown impact	$864	230	Reference to an Impt file of level 0
+Footstep turn impact	$8E6	230	Reference to an Impt file of level 0
+Footstep run start impact	$968	230	Reference to an Impt file of level 0
+Footstep single step impact	$9EA	230	Reference to an Impt file of level 0
+Footstep run stop impact	$A6C	230	Reference to an Impt file of level 0
+Footstep walk stop impact	$AEE	230	Reference to an Impt file of level 0
+Footstep run sprint impact	$B70	230	Reference to an Impt file of level 0
+Special death particles	$BF4	164	Reference to a 3Dparticle.BINA file of level 0; only the mad bomber use it
+TRBS-link	$C3C	12	Body set link
+TRMA-link	$C40	12	Texture map array link
+CBPM-link	$C44	12	Body part material link
+CBPI-link	$C48	12	Body part impact link
+Peace timer	$C4C	4	Peace timer in 1/60 seconds; after that time the character switches back from fight to peace mode
+First idle timer	$C50	4	First idle timer in 1/60 seconds; after that time Oni plays a special idle animation
+Second idle timer	$C54	4	Second idle timer in 1/60 seconds; after that time Oni plays a special idle animation
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Basic health	$C5C	4	Unknown; always the same
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+TRAC-link	$C88	8	Animation collection link
+TRSC-link	$C8C	8	Screen (aiming) collection link
+
+*Unknown
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	2	Unknown
+Unknown	$1E	2	Unknown
+Unknown	$20	9	Unknown
+Unknown	$24	9	Unknown
+Unknown	$44	9	Unknown; always the same
+Unknown	$48	1	Unknown
+Unknown	$49	1	Unknown; always the same
+Unknown	$4C	9	Unknown; always the same
+Unknown	$50	9	Unknown; always the same
+Unknown	$54	9	Unknown; always the same
+Unknown	$58	9	Unknown; always the same
+Unknown	$5C	9	Unknown; always the same
+Unknown	$60	9	Unknown; always the same
+Unknown	$68	9	Unknown; always the same
+Unknown	$6C	9	Unknown; always the same
+Unknown	$70	9	Unknown; always the same
+Unknown	$74	9	Unknown; always the same
+Unknown	$78	9	Unknown; always the same
+Unknown	$7C	2	Unknown; always the same
+Unknown	$7E	2	Unknown; always the same
+Unknown	$80	2	Unknown; always the same
+Unknown	$82	2	Unknown; always the same
+Unknown	$84	2	Unknown; always the same
+Unknown	$86	2	Unknown; always the same
+Unknown	$88	2	Unknown; always the same
+Unknown	$8A	2	Unknown; always the same
+Unknown	$8C	2	Unknown; always the same
+Unknown	$8E	2	Unknown; always the same
+Unknown	$90	2	Unknown; always the same
+Unknown	$92	1	Unknown; always the same
+Unknown	$94	9	Unknown; always the same
+Unknown	$118	4	Unknown; always the same
+Unknown	$11C	4	Unknown; always the same
+Unknown	$120	4	Unknown; always the same
+Unknown	$124	4	Unknown; always the same
+Unknown	$128	4	Unknown
+Unknown	$130	2	Unknown
+Unknown	$132	2	Unknown
+Unknown	$134	4	Unknown
+Unknown	$138	9	Unknown
+Unknown	$13C	9	Unknown
+Unknown	$140	9	Unknown; always the same
+Unknown	$144	9	Unknown; always the same
+Unknown	$148	9	Unknown; always the same
+Unknown	$14C	4	Unknown
+Unknown	$150	4	Unknown
+Unknown	$154	4	Unknown
+Unknown	$158	4	Unknown
+Unknown	$404	9	Unknown
+Unknown	$408	9	Unknown
+Unknown	$40C	9	Unknown
+Unknown	$410	9	Unknown; always the same
+Unknown	$414	9	Unknown; always the same
+Unknown	$418	4	Unknown; always the same
+Unknown	$41C	4	Unknown; always the same
+Unknown	$420	4	Unknown; always the same
+Unknown	$424	4	Unknown; always the same
+Unknown	$428	4	Unknown; always the same
+Unknown	$42C	4	Unknown; always the same
+Unknown	$430	9	Unknown; always the same
+Unknown	$294	4	Unknown; always the same
+Unknown	$298	4	Unknown; always the same
+Unknown	$29C	4	Unknown; always the same
+Unknown	$2A0	4	Unknown; always the same
+Unknown	$2A4	4	Unknown
+Unknown	$2A8	4	Unknown
+Unknown	$2AC	2	Unknown
+Unknown	$2AE	2	Unknown
+Unknown	$440	4	Unknown; maybe a canceled link; always the same
+Unknown	$444	10016	Maybe the weight of the character?
+Unknown	$BF2	2	Unknown; always the same; maybe only a filler
+Unknown	$C34	4	Unknown; maybe a canceled link; always the same
+Unknown	$C38	4	Unknown; maybe a canceled link; always the same
+Unknown	$C68	9	Unknown; always the same
+Unknown	$C6C	9	Unknown; always the same
+Unknown	$C70	9	Unknown
+Unknown	$C74	9	Unknown
+Unknown	$C78	9	Unknown; always the same
+Unknown	$C7C	9	Unknown; always the same
+Unknown	$C80	9	Unknown; always the same
+Unknown	$C84	9	Unknown
+Unknown	$C90	2	Unknown; always the same
+Unknown	$C92	2	Unknown; only the mad bomber use it
+Unknown	$C94	1	Unknown
+Unknown	$C95	1	Unknown
+Unknown	$C96	1	Unknown
+Unknown	$C97	1	Unknown
+
+*Unused
+Not used	$4A	1002	Not used
+Not used	$66	1002	Not used
+Not used	$93	1001	Not used
+Not useed	$C98	1008	Not used
+
+
+*Unknown Block1
+Block 1 - Unknown	$15C	9	Unknown
+Block 1 - Unknown	$160	9	Unknown
+Block 1 - Unknown	$164	9	Unknown; always the same
+Block 1 - Unknown	$168	9	Unknown
+Block 1 - Unknown	$16C	9	Unknown
+Block 1 - Unknown	$170	2	Unknown; always the same
+Block 1 - Unknown	$172	2	Unknown; always the same
+*Unknown Block2
+Block 2 - Unknown	$174	9	Unknown
+Block 2 - Unknown	$178	9	Unknown
+Block 2 - Unknown	$17C	9	Unknown
+Block 2 - Unknown	$180	9	Unknown
+Block 2 - Unknown	$184	9	Unknown
+Block 2 - Unknown	$188	2	Unknown; always the same
+Block 2 - Unknown	$18A	2	Unknown; always the same
+*Unknown Block3
+Block 3 - Unknown	$18C	9	Unknown
+Block 3 - Unknown	$190	9	Unknown
+Block 3 - Unknown	$194	9	Unknown; always the same
+Block 3 - Unknown	$198	9	Unknown
+Block 3 - Unknown	$19C	9	Unknown
+Block 3 - Unknown	$1A0	2	Unknown; always the same
+Block 3 - Unknown	$1A2	2	Unknown; always the same
+*Unknown Block4
+Block 4 - Unknown	$1A4	9	Unknown
+Block 4 - Unknown	$1A8	9	Unknown
+Block 4 - Unknown	$1AC	9	Unknown; always the same
+Block 4 - Unknown	$1B0	9	Unknown
+Block 4 - Unknown	$1B4	9	Unknown
+Block 4 - Unknown	$1B8	2	Unknown
+Block 4 - Unknown	$1BA	2	Unknown
+*Unknown Block5
+Block 5 - Unknown	$1BC	9	Unknown; always the same
+Block 5 - Unknown	$1C0	9	Unknown
+Block 5 - Unknown	$1C4	9	Unknown
+Block 5 - Unknown	$1C8	9	Unknown
+Block 5 - Unknown	$1CC	9	Unknown
+Block 5 - Unknown	$1D0	2	Unknown
+Block 5 - Unknown	$1D2	2	Unknown
+*Unknown Block6
+Block 6 - Unknown	$1D4	9	Unknown
+Block 6 - Unknown	$1D8	9	Unknown
+Block 6 - Unknown	$1DC	9	Unknown
+Block 6 - Unknown	$1E0	9	Unknown
+Block 6 - Unknown	$1E4	9	Unknown
+Block 6 - Unknown	$1E8	2	Unknown
+Block 6 - Unknown	$1EA	2	Unknown
+*Unknown Block7
+Block 7 - Unknown	$1EC	9	Unknown; always the same
+Block 7 - Unknown	$1F0	9	Unknown
+Block 7 - Unknown	$1F4	9	Unknown
+Block 7 - Unknown	$1F8	9	Unknown
+Block 7 - Unknown	$1FC	9	Unknown; always the same
+Block 7 - Unknown	$200	2	Unknown; always the same
+Block 7 - Unknown	$202	2	Unknown; always the same
+*Unknown Block8
+Block 8 - Unknown	$204	9	Unknown
+Block 8 - Unknown	$208	9	Unknown
+Block 8 - Unknown	$20C	9	Unknown
+Block 8 - Unknown	$210	9	Unknown; always the same
+Block 8 - Unknown	$214	9	Unknown
+Block 8 - Unknown	$218	2	Unknown
+Block 8 - Unknown	$21A	2	Unknown
+*Unknown Block9
+Block 9 - Unknown	$21C	9	Unknown
+Block 9 - Unknown	$220	9	Unknown
+Block 9 - Unknown	$224	9	Unknown
+Block 9 - Unknown	$228	9	Unknown
+Block 9 - Unknown	$22C	9	Unknown
+Block 9 - Unknown	$230	2	Unknown
+Block 9 - Unknown	$232	2	Unknown
+*Unknown Block10
+Block 10 - Unknown	$234	9	Unknown
+Block 10 - Unknown	$238	9	Unknown
+Block 10 - Unknown	$23C	9	Unknown
+Block 10 - Unknown	$240	9	Unknown
+Block 10 - Unknown	$244	9	Unknown
+Block 10 - Unknown	$248	2	Unknown
+Block 10 - Unknown	$24A	2	Unknown
+*Unknown Block11
+Block 11 - Unknown	$24C	9	Unknown
+Block 11 - Unknown	$250	9	Unknown
+Block 11 - Unknown	$254	9	Unknown; always the same
+Block 11 - Unknown	$258	9	Unknown
+Block 11 - Unknown	$25C	9	Unknown; always the same
+Block 11 - Unknown	$260	2	Unknown; always the same
+Block 11 - Unknown	$262	2	Unknown; always the same
+*Unknown Block12
+Block 12 - Unknown	$264	9	Unknown
+Block 12 - Unknown	$268	9	Unknown
+Block 12 - Unknown	$26C	9	Unknown; always the same
+Block 12 - Unknown	$270	9	Unknown
+Block 12 - Unknown	$274	9	Unknown; always the same
+Block 12 - Unknown	$278	2	Unknown; always the same
+Block 12 - Unknown	$27A	2	Unknown; always the same
+*Unknown Block13
+Block 13 - Unknown	$27C	9	Unknown
+Block 13 - Unknown	$280	9	Unknown
+Block 13 - Unknown	$284	9	Unknown; always the same
+Block 13 - Unknown	$288	9	Unknown
+Block 13 - Unknown	$28C	9	Unknown; always the same
+Block 13 - Unknown	$290	2	Unknown; always the same
+Block 13 - Unknown	$292	2	Unknown; always the same
Index: /oup/structdefs/06-04-24/ONCC_2.txt
===================================================================
--- /oup/structdefs/06-04-24/ONCC_2.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONCC_2.txt	(revision 8)
@@ -0,0 +1,258 @@
+Oni Character Class
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	9	Unknown; always the same; maybe downwards velocity?
+Downward acceleration	$0C	9	Downward gravity acceleration
+Starting velocity	$10	9	Starting velocity for a simple (tap) JUMP
+Limit velocity	$14	9	Limit velocity for jumping and gravity flight 
+Upward acceleration	$18	9	Upward acceleration (jetpack) if you hold JUMP
+Unknown	$1C	2	Unknown; always the same; maybe a gravity timer?
+Jetpack timer	$1E	2	Jetpack timer; time during which you can use the jetpack
+Height no damage	$20	9	Maximal falling height without damage 
+Height damage	$24	9	Maximal falling height with damage
+TXMP-link	$28	12	Link to the shadow texture
+Shadow height 5 	$2C	9	Height, where the shadow fades out completely
+Shadow height 4	$30	9	Height, where the diameter of the shadow decreases and the shadow fades out half
+Shadow height 3	$34	9	Height, where the diameter of the shadow decreases
+Shadow height 2	$38	9	Height, where the diameter of the shadow decreases
+Shadow height 1	$3C	9	Height, where the diameter of the shadow decreases
+Shadow option 1	$40	2	Transparency of the shadow for the first part of a jump
+Shadow option 2	$42	2	Transparency of the shadow for the second part of a jump
+Unknown	$44	9	Unknown; always the same
+Unknown	$48	1	Unknown
+Unknown	$49	1	Unknown; always the same
+Not used	$4A	1002	Not used
+Unknown	$4C	9	Unknown; always the same
+Unknown	$50	9	Unknown; always the same
+Unknown	$54	9	Unknown; always the same
+Unknown	$58	9	Unknown; always the same
+Unknown	$5C	9	Unknown; always the same
+Unknown	$60	9	Unknown; always the same
+Regeneration time	$64	2	Regeneration time of one health point in 1/60 seconds if you use a hypo
+Not used	$66	1002	Not used
+Unknown	$68	9	Unknown; always the same
+Unknown	$6C	9	Unknown; always the same
+Unknown	$70	9	Unknown; always the same
+Unknown	$74	9	Unknown; always the same
+Unknown	$78	9	Unknown; always the same
+Unknown	$7C	2	Unknown; always the same
+Unknown	$7E	2	Unknown; always the same
+Unknown	$80	2	Unknown; always the same
+Unknown	$82	2	Unknown; always the same
+Unknown	$84	2	Unknown; always the same
+Unknown	$86	2	Unknown; always the same
+Unknown	$88	2	Unknown; always the same
+Unknown	$8A	2	Unknown; always the same
+Unknown	$8C	2	Unknown; always the same
+Unknown	$8E	2	Unknown; always the same
+Unknown	$90	2	Unknown; always the same
+Unknown	$92	1	Unknown; always the same
+Not used	$93	1001	Not used
+Unknown	$94	9	Unknown; always the same
+Hurt light sound	$98	132	Reference to an OSBD file of level 0
+Hurt medium sound	$B8	132	Reference to an OSBD file of level 0
+Hurt heavy sound	$D8	132	Reference to an OSBD file of level 0
+Death sound	$F8	132	Reference to an OSBD file of level 0
+Unknown	$118	4	Unknown; always the same
+Unknown	$11C	4	Unknown; always the same
+Unknown	$120	4	Unknown; always the same
+Unknown	$124	4	Unknown; always the same
+Unknown	$128	4	Unknown
+Rotation factor	$12C	9	Rotation factor * 360 degrees = possible rotation per frame or animation
+Unknown	$130	2	Unknown
+Unknown	$132	2	Unknown
+Unknown	$134	4	Unknown
+Unknown	$138	9	Unknown
+Unknown	$13C	9	Unknown
+Unknown	$140	9	Unknown; always the same
+Unknown	$144	9	Unknown; always the same
+Unknown	$148	9	Unknown; always the same
+Unknown	$14C	4	Unknown
+Unknown	$150	4	Unknown
+Unknown	$154	4	Unknown
+Unknown	$158	4	Unknown
+w0_sec - recoil	$15C	9	recoil compensation amount (0 = min, 1 = max)
+w0_sec - best angle	$160	9	best aiming angle in radians
+w0_sec - error	$164	9	shot grouping error
+w0_sec - decay	$168	9	shot grouping decay
+w0_sec - inaccuracy	$16C	9	shooting inaccuracy multiplier
+w0_sec - minimum delay	$170	2	minimum delay between shots in frames
+w0_sec - maximum delay	$172	2	maximum delay between shots in frames
+w1_tap - recoil	$174	9	recoil compensation amount (0 = min, 1 = max)
+w1_tap - best angle	$178	9	best aiming angle in radians
+w1_tap - error	$17C	9	shot grouping error
+w1_tap - decay	$180	9	shot grouping decay
+w1_tap - inaccuracy	$184	9	shooting inaccuracy multiplier
+w1_tap - minimum delay	$188	2	minimum delay between shots in frames
+w1_tap - maximum delay	$18A	2	maximum delay between shots in frames
+w2_sap - recoil	$18C	9	recoil compensation amount (0 = min, 1 = max)
+w2_sap - best angle	$190	9	best aiming angle in radians
+w2_sap - error	$194	9	shot grouping error
+w2_sap - decay	$198	9	shot grouping decay
+w2_sap - inaccuracy	$19C	9	shooting inaccuracy multiplier
+w2_sap - minimum delay	$1A0	2	minimum delay between shots in frames
+w2_sap - maximum delay	$1A2	2	maximum delay between shots in frames
+w3_phr - recoil	$1A4	9	recoil compensation amount (0 = min, 1 = max)
+w3_phr - best angle	$1A8	9	best aiming angle in radians
+w3_phr - error	$1AC	9	shot grouping error
+w3_phr - decay	$1B0	9	shot grouping decay
+w3_phr - inaccuracy	$1B4	9	shooting inaccuracy multiplier
+w3_phr - minimum delay	$1B8	2	minimum delay between shots in frames
+w3_phr - maximum delay	$1BA	2	maximum delay between shots in frames
+w4_psm - recoil	$1BC	9	recoil compensation amount (0 = min, 1 = max)
+w4_psm - best angle	$1C0	9	best aiming angle in radians
+w4_psm - error	$1C4	9	shot grouping error
+w4_psm - decay	$1C8	9	shot grouping decay
+w4_psm - inaccuracy	$1CC	9	shooting inaccuracy multiplier
+w4_psm - minimum delay	$1D0	2	minimum delay between shots in frames
+w4_psm - maximum delay	$1D2	2	maximum delay between shots in frames
+w5_sbg - recoil	$1D4	9	recoil compensation amount (0 = min, 1 = max)
+w5_sbg - best angle	$1D8	9	best aiming angle in radians
+w5_sbg - error	$1DC	9	shot grouping error
+w5_sbg - decay	$1E0	9	shot grouping decay
+w5_sbg - inaccuracy	$1E4	9	shooting inaccuracy multiplier
+w5_sbg - minimum delay	$1E8	2	minimum delay between shots in frames
+w5_sbg - maximum delay	$1EA	2	maximum delay between shots in frames
+w6_vdg - recoil	$1EC	9	recoil compensation amount (0 = min, 1 = max)
+w6_vdg - best angle	$1F0	9	best aiming angle in radians
+w6_vdg - error	$1F4	9	shot grouping error
+w6_vdg - decay	$1F8	9	shot grouping decay
+w6_vdg - inaccuracy	$1FC	9	shooting inaccuracy multiplier
+w6_vdg - minimum delay	$200	2	minimum delay between shots in frames
+w6_vdg - maximum delay	$202	2	maximum delay between shots in frames
+w7_scc - recoil	$204	9	recoil compensation amount (0 = min, 1 = max)
+w7_scc - best angle	$208	9	best aiming angle in radians
+w7_scc - error	$20C	9	shot grouping error
+w7_scc - decay	$210	9	shot grouping decay
+w7_scc - inaccuracy	$214	9	shooting inaccuracy multiplier
+w7_scc - minimum delay	$218	2	minimum delay between shots in frames
+w7_scc - maximum delay	$21A	2	maximum delay between shots in frames
+w8_mbo - recoil	$21C	9	recoil compensation amount (0 = min, 1 = max)
+w8_mbo - best angle	$220	9	best aiming angle in radians
+w8_mbo - error	$224	9	shot grouping error
+w8_mbo - decay	$228	9	shot grouping decay
+w8_mbo - inaccuracy	$22C	9	shooting inaccuracy multiplier
+w8_mbo - minimum delay	$230	2	minimum delay between shots in frames
+w8_mbo - maximum delay	$232	2	maximum delay between shots in frames
+w9_scr - recoil	$234	9	recoil compensation amount (0 = min, 1 = max)
+w9_scr - best angle	$238	9	best aiming angle in radians
+w9_scr - error	$23C	9	shot grouping error
+w9_scr - decay	$240	9	shot grouping decay
+w9_scr - inaccuracy	$244	9	shooting inaccuracy multiplier
+w9_scr - minimum delay	$248	2	minimum delay between shots in frames
+w9_scr - maximum delay	$24A	2	maximum delay between shots in frames
+w10_sni - recoil	$24C	9	recoil compensation amount (0 = min, 1 = max)
+w10_sni - best angle	$250	9	best aiming angle in radians
+w10_sni - error	$254	9	shot grouping error
+w10_sni - decay	$258	9	shot grouping decay
+w10_sni - inaccuracy	$25C	9	shooting inaccuracy multiplier
+w10_sni - minimum delay	$260	2	minimum delay between shots in frames
+w10_sni - maximum delay	$262	2	maximum delay between shots in frames
+w11_ba1 - recoil	$264	9	recoil compensation amount (0 = min, 1 = max)
+w11_ba1 - best angle	$268	9	best aiming angle in radians
+w11_ba1 - error	$26C	9	shot grouping error
+w11_ba1 - decay	$270	9	shot grouping decay
+w11_ba1 - inaccuracy	$274	9	shooting inaccuracy multiplier
+w11_ba1 - minimum delay	$278	2	minimum delay between shots in frames
+w11_ba1 - maximum delay	$27A	2	maximum delay between shots in frames
+w12_ba2 - recoil	$27C	9	recoil compensation amount (0 = min, 1 = max)
+w12_ba2 - best angle	$280	9	best aiming angle in radians
+w12_ba2 - error	$284	9	shot grouping error
+w12_ba2 - decay	$288	9	shot grouping decay
+w12_ba2 - inaccuracy	$28C	9	shooting inaccuracy multiplier
+w12_ba2 - minimum delay	$290	2	minimum delay between shots in frames
+w12_ba2 - maximum delay	$292	2	maximum delay between shots in frames
+Unknown	$294	4	Unknown; always the same
+Unknown	$298	4	Unknown; always the same
+Unknown	$29C	4	Unknown; always the same
+Unknown	$2A0	4	Unknown; always the same
+Unknown	$2A4	4	Unknown
+Unknown	$2A8	4	Unknown
+Unknown	$2AC	2	Unknown
+Unknown	$2AE	2	Unknown
+Taunt sound query	$2B0	1	0 = not used; 100 = used
+Alert sound query	$2B1	1	0 = not used; 100 = used
+Startle sound query	$2B2	1	0 = not used; 100 = used
+Check body sound query	$2B3	1	0 = not used; 100 = used
+Pursue sound query	$2B4	1	0 = not used; 100 = used
+Cower sound query	$2B5	1	0 = not used; 100 = used
+Punch heavy sound query	$2B6	1	0 = not used; 100 = used
+Kich heavy sound query	$2B7	1	0 = not used; 100 = used
+Super3 sound query	$2B8	1	0 = not used; 100 = used
+Super4 sound query	$2B9	1	0 = not used; 100 = used
+Taunt sound	$2BC	132	Reference to a SNDD file of level 0
+Alert sound	$2DC	132	Reference to a SNDD file of level 0
+Startle sound	$2FC	132	Reference to a SNDD file of level 0
+Check body sound	$31C	132	Reference to a SNDD file of level 0
+Pursue sound	$33C	132	Reference to a SNDD file of level 0
+Cower sound	$35C	132	Reference to a SNDD file of level 0
+Punch heavy sound	$37C	132	Reference to a SNDD file of level 0
+Kick heavy sound	$39C	132	Reference to a SNDD file of level 0
+Super3 sound	$3BC	132	Reference to a SNDD file of level 0
+Super4 sound	$3DC	132	Reference to a SNDD file of level 0
+Eyeshot	$3FC	9	The max. distance where the AI can see you
+Earshot	$400	9	The max. distance where the AI can hear you
+Unknown	$404	9	Unknown
+Unknown	$408	9	Unknown
+Unknown	$40C	9	Unknown
+Unknown	$410	9	Unknown; always the same
+Unknown	$414	9	Unknown; always the same
+Unknown	$418	4	Unknown; always the same
+Unknown	$41C	4	Unknown; always the same
+Unknown	$420	4	Unknown; always the same
+Unknown	$424	4	Unknown; always the same
+Unknown	$428	4	Unknown; always the same
+Unknown	$42C	4	Unknown; always the same
+Unknown	$430	9	Unknown; always the same
+ONCV-link	$434	12	Link to the Character Varient
+ONCP-link	$438	12	Link to the Character Particle Array
+ONIA-link	$43C	12	Link to the Character Impact Array
+Unknown	$440	4	Unknown; maybe a canceled link; always the same
+Unknown	$444	10016	Maybe the weight of the character?
+Footstep walk impact	$454	230	Reference to an Impt file of level 0
+Footstep run impact	$4D6	230	Reference to an Impt file of level 0
+Footstep crouch impact	$558	230	Reference to an Impt file of level 0
+Fall slide impact	$5DA	230	Reference to an Impt file of level 0
+Fall land impact	$65C	230	Reference to an Impt file of level 0
+Fall land hard impact	$6DE	230	Reference to an Impt file of level 0
+Fall knockdown impact	$760	230	Reference to an Impt file of level 0
+Fall knockdown impact	$7E2	230	Reference to an Impt file of level 0
+Fall knockdown impact	$864	230	Reference to an Impt file of level 0
+Footstep turn impact	$8E6	230	Reference to an Impt file of level 0
+Footstep run start impact	$968	230	Reference to an Impt file of level 0
+Footstep single step impact	$9EA	230	Reference to an Impt file of level 0
+Footstep run stop impact	$A6C	230	Reference to an Impt file of level 0
+Footstep walk stop impact	$AEE	230	Reference to an Impt file of level 0
+Footstep run sprint impact	$B70	230	Reference to an Impt file of level 0
+Unknown	$BF2	2	Unknown; always the same; maybe only a filler
+Special death particles	$BF4	164	Reference to a 3Dparticle.BINA file of level 0; only the mad bomber use it
+Unknown	$C34	4	Unknown; maybe a canceled link; always the same
+Unknown	$C38	4	Unknown; maybe a canceled link; always the same
+TRBS-link	$C3C	12	Link to the Body Set
+TRMA-link	$C40	12	Link to the Texture Map Array
+CBPM-link	$C44	12	Link to the Body Part Material
+CBPI-link	$C48	12	Link to the Body Part Impacts
+Peace timer	$C4C	4	Peace timer in 1/60 seconds; after that time the character switches back from fight to peace mode
+First idle timer	$C50	4	First idle timer in 1/60 seconds; after that time Oni plays a special idle animation
+Second idle timer	$C54	4	Second idle timer in 1/60 seconds; after that time Oni plays a special idle animation
+Basic health	$C58	4	Extra health informations are stored in the Character.BINA files
+Basic health	$C5C	4	Unknown; always the same
+Minimal body size factor	$C60	9	Minimal body size factor
+Maximal body size factor	$C64	9	Maximal body size factor
+Unknown	$C68	9	Unknown; always the same
+Unknown	$C6C	9	Unknown; always the same
+Unknown	$C70	9	Unknown
+Unknown	$C74	9	Unknown
+Unknown	$C78	9	Unknown; always the same
+Unknown	$C7C	9	Unknown; always the same
+Unknown	$C80	9	Unknown; always the same
+Unknown	$C84	9	Unknown
+TRAC-link	$C88	12	Link to the Animation Collection
+TRSC-link	$C8C	12	Link to the Screen (Aiming) Collection
+Unknown	$C90	2	Unknown; always the same
+Unknown	$C92	2	Unknown; only the mad bomber use it
+Unknown	$C94	1	Unknown
+Unknown	$C95	1	Unknown
+Unknown	$C96	1	Unknown
+Unknown	$C97	1	Unknown
+Not useed	$C98	1008	Not used
Index: /oup/structdefs/06-04-24/ONCP.txt
===================================================================
--- /oup/structdefs/06-04-24/ONCP.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONCP.txt	(revision 8)
@@ -0,0 +1,12 @@
+Oni Character Particle Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	88
+Particle name	$00	10016	Name of the particle (all entries after the first 00 are useless)
+Particle reference	$10	164	Reference to a BINA file of level 0
+Bodypart	$50	14	Particle is fixed to this bodypart
+Unknown	$52	2	Unknown
+Unknown	$54	4	Unknown
+
Index: /oup/structdefs/06-04-24/ONCV.txt
===================================================================
--- /oup/structdefs/06-04-24/ONCV.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONCV.txt	(revision 8)
@@ -0,0 +1,7 @@
+Oni Character Variant
+File id	$00	12	File id
+Level id	$04	17	Level id
+ONCV-link	$08	12	Link to the next higher Character Variant
+Basic character type	$0C	132	Basic character type
+Upgrade character type	$2C	132	Upgrade character type; used when you play on hard and the "upgrade difficulty" bit in the Character.BINA file is set
+Not used	$4C	1020	Not used
Index: /oup/structdefs/06-04-24/ONFA.txt
===================================================================
--- /oup/structdefs/06-04-24/ONFA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONFA.txt	(revision 8)
@@ -0,0 +1,25 @@
+Imported Flag Node Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages used	$1C	2	Amount of packages that follow
+Packages possible	$1E	2	Amount of packages that are possible
+*Package		$20	$1C	2	68
+Unknown	$00	9	Unknown
+Unknown	$04	9	Unknown
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	9	Unknown
+Unknown	$20	9	Unknown
+x-position	$24	9	x-position
+y-position	$28	9	y-position (height)
+z-position	$2C	9	z-position
+x-position again	$30	9	x-position again
+y-position again	$34	9	y-position (height) again
+z-position again	$38	9	z-position again
+Unknown	$3C	9	Unknown
+Flag node id	$40	2	Id of the flag node
+Unknown	$42	2	Unknown
Index: /oup/structdefs/06-04-24/ONGS.txt
===================================================================
--- /oup/structdefs/06-04-24/ONGS.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONGS.txt	(revision 8)
@@ -0,0 +1,93 @@
+Oni Game Settings
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	4	Unknown
+Unknown	$20	4	Unknown
+Unknown	$24	9	Unknown
+Unknown	$28	9	Unknown
+Unknown	$2C	9	Unknown
+Not used	$30	1048	Not used
+Unknown	$60	16	Unknown
+Unknown	$64	16	Unknown
+Unknown	$68	16	Unknown
+Unknown	$6C	16	Unknown
+Not used	$70	1048	Not used
+Ammo model reference	$A0	228	Reference to the ammo model
+Cell model reference	$120	228	Reference to the cell model
+Hypo model reference	$1A0	228	Reference to the hypo model
+Shield model reference	$220	228	Reference to the force shield model
+Invis model reference	$2A0	228	Reference to the phase cloak model
+Lsi model reference	$320	228	Reference to the lsi model
+Not used	$3A0	1128	Not used; maybe a canceled model reference
+Ammo texture reference	$420	228	Reference to the texture that surrounds the ammo
+Cell texture reference	$4A0	228	Reference to the texture that surrounds the cell
+Hypo texture reference	$520	228	Reference to the texture that surrounds the hypo
+Shield texture reference	$5A0	228	Reference to the texture that surrounds the force shield
+Invis texture reference	$620	228	Reference to the texture that surrounds the phase cloak
+Lsi texture reference	$6A0	228	Reference to the texture that surrounds the lsi
+Not used	$720	1128	Not used; maybe a canceled texture reference
+Unknown	$7A0	9	Unknown
+Unknown	$7A4	9	Unknown
+Unknown	$7A8	9	Unknown
+Unknown	$7AC	9	Unknown
+Unknown	$7B0	9	Unknown
+Unknown	$7B4	9	Unknown
+Unknown	$7B8	9	Unknown
+Unknown	$7BC	9	Unknown
+Unknown	$7C0	9	Unknown
+Unknown	$7C4	9	Unknown
+Unknown	$7C8	9	Unknown
+Unknown	$7CC	9	Unknown
+Not used	$7D0	1008	Not used
+Empty sound field	$7D8	132	Empty reference to an OSBD file
+Door fail sound	$7F8	132	Reference to the door_fail OSBD file
+Door lock sound	$818	132	Reference to the door_lock OSBD file
+Empty sound field	$838	132	Empty reference to an OSBD file
+Use hypo sound	$858	132	Reference to the use_hypo OSBD file
+Empty sound field	$878	132	Empty reference to an OSBD file
+Inventory fail sound	$898	132	Reference to the inventory_fail  OSBD file
+Receive ammo sound	$8B8	132	Reference to the receive_ammo OSBD file
+Receive cell sound	$8D8	132	Reference to the receive_cell OSBD file
+Receive hypo sound	$8F8	132	Reference to the receive_hypo OSBD file
+Receive lsi sound	$918	132	Reference to the receive_lsi OSBD file
+Compass sound	$938	132	Reference to the compass OSBD file
+Objective new sound	$958	132	Reference to the objective_new OSBD file
+Objective prompt sound	$978	132	Reference to the objective_prompt OSBD file
+Objective complete sound	$998	132	Reference to the objective_complete OSBD file
+Autosave sound	$9B8	132	Reference to the autosave OSBD file
+Empty sound field	$9D8	132	Empty reference to an OSBD file
+Empty sound field	$9F8	132	Empty reference to an OSBD file
+Health low sound	$A18	132	Reference to the health_low OSBD file
+Health over sound	$A38	132	Reference to the health_over OSBD file
+Shield sound	$A58	132	Reference to the shield  OSBD file
+Invis sound	$A78	132	Reference to the invisibility OSBD file
+Empty sound field	$A98	132	Empty reference to an OSBD file
+Unknown	$AB8	9	Unknown
+Unknown	$ABC	9	Unknown
+Unknown	$AC0	9	Unknown
+Unknown	$AC4	9	Unknown
+Unknown	$AC8	9	Unknown
+Unknown	$ACC	9	Unknown
+Unknown	$AD0	9	Unknown
+Unknown	$AD4	9	Unknown
+Unknown	$AD8	9	Unknown
+Unknown	$ADC	9	Unknown
+Unknown	$AE0	9	Unknown
+Unknown	$AE4	9	Unknown
+Unknown	$AE8	9	Unknown
+Unknown	$AEC	9	Unknown
+Unknown	$AF0	9	Unknown
+Unknown	$AF4	9	Unknown
+Unknown	$AF8	9	Unknown
+Unknown	$AFC	9	Unknown
+Packages	$B00	4	Amount of packages that follow
+*Package		$B04	$B00	4	68
+Item name	$00	10032	Name of the item
+First level	$20	2	First level with autoprompting
+Last level	$22	2	Last level with autoprompting
+Raw file anchor	$24	10032	Raw file anchor for the text message (it belongs to the SUBT file)
Index: /oup/structdefs/06-04-24/ONIA.txt
===================================================================
--- /oup/structdefs/06-04-24/ONIA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONIA.txt	(revision 8)
@@ -0,0 +1,11 @@
+Oni Character Impact Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	164
+Particle name	$00	10016	Name of the particle
+Impact reference	$10	228	Reference to an Impt file of level 0
+Sound reference	$90	116	Reference to an OSBD file of level 0
+Unknown	$A0	2	Unknown
+Unknown	$A2	2	Unknown
Index: /oup/structdefs/06-04-24/ONLD.txt
===================================================================
--- /oup/structdefs/06-04-24/ONLD.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONLD.txt	(revision 8)
@@ -0,0 +1,7 @@
+Oni Level Descriptor
+File id	$00	12	File id
+Level id	$04	17	Level id
+Current level	$08	2	Id of current level
+Next level	$0A	2	Id of the level that follows
+Level name	$0C	10064	Name of the level; you'll find it in the list, when you load a level
+Not used	$4C	1020	Not used
Index: /oup/structdefs/06-04-24/ONLV.txt
===================================================================
--- /oup/structdefs/06-04-24/ONLV.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONLV.txt	(revision 8)
@@ -0,0 +1,20 @@
+Oni Level Descriptor
+File id	$00	12	File id
+Level id	$04	17	Level id
+Level name	$08	10064	Name of the level
+AKEV-Link	$48	12	Link to the Environment
+OBOA-Link	$4C	12	Link to the Starting Object Array
+ONMA-Link	$50	12	Link to the Imported Marker Node Array
+ONFA-Link	$54	12	Link to the Imported Flag Node Array
+ONTA-Link	$58	12	Link to the Trigger Array
+ONSK-Link	$5C	12	Link to the Sky Class
+Unknown	$60	12	Unknown; maybe a canceled link; always the same
+AISA-Link	$64	12	Link to the AI Character Setup Array
+AITR-Link	$68	12	Link to the AI Script Trigger Array
+ONSA-Link	$6C	12	Link to the Imported Spawn Array
+OBDC-Link	$70	12	Link to the Door Class Array
+ONOA-Link	$74	12	Link to the Object Gunk Array
+ENVP-Link	$78	12	Link to the Environment Particle Array
+Not used	$7C	1644	Not used
+CRSA-Link	$300	12	Link to the Corpse Array
+Not used	$304	1028	Not used
Index: /oup/structdefs/06-04-24/ONMA.txt
===================================================================
--- /oup/structdefs/06-04-24/ONMA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONMA.txt	(revision 8)
@@ -0,0 +1,13 @@
+Imported Marker Node Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	88
+Light name	$00	10064	Name of the light
+x-position	$40	9	x-position of the light
+y-position	$44	9	y-position (height) of the light
+z-position	$48	9	z-position of the light
+Unknown	$4C	9	Unknown
+Unknown	$50	9	Unknown
+Unknown	$54	9	Unknown
Index: /oup/structdefs/06-04-24/ONOA.txt
===================================================================
--- /oup/structdefs/06-04-24/ONOA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONOA.txt	(revision 8)
@@ -0,0 +1,9 @@
+Object Gunk Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	8
+Unknown	$00	14	Unknown
+Unknown	$02	14	Unknown
+IDXA-link	$04	12	Link to the Index Array
Index: /oup/structdefs/06-04-24/ONSA.txt
===================================================================
--- /oup/structdefs/06-04-24/ONSA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONSA.txt	(revision 8)
@@ -0,0 +1,7 @@
+Imported Spawn Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	2
+Unknown	$00	2	Unknown
Index: /oup/structdefs/06-04-24/ONSK.txt
===================================================================
--- /oup/structdefs/06-04-24/ONSK.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONSK.txt	(revision 8)
@@ -0,0 +1,39 @@
+Oni Sky Class
+File id	$00	12	File id
+Level id	$04	17	Level id
+TXMP-link	$08	12	Link to the top texture
+TXMP-link	$0C	12	Link to the left texture
+TXMP-link	$10	12	Link to the right texture
+TXMP-link	$14	12	Link to the front texture
+TXMP-link	$18	12	Link to the back texture
+Not used	$1C	1004	Not used; maybe a canceled link
+TXMP-link	$20	12	Link to the sun texture (not used in the game)
+Not used	$24	1004	Not used; maybe a canceled link
+Not used	$28	1004	Not used; maybe a canceled link
+Not used	$2C	1004	Not used; maybe a canceled link
+Not used	$30	1004	Not used; maybe a canceled link
+Not used	$34	1004	Not used; maybe a canceled link
+Not used	$38	1004	Not used; maybe a canceled link
+Not used	$3C	1004	Not used; maybe a canceled link
+Not used	$40	1004	Not used; maybe a canceled link
+TXMP-link	$44	12	Link to the lensflare texture (not used in the game)
+Not used	$48	1004	Not used; maybe a canceled link
+Not used	$4C	1004	Not used; maybe a canceled link
+Not used	$50	1004	Not used; maybe a canceled link
+Not used	$54	1004	Not used; maybe a canceled link
+Unknown	$58	4	Unknown
+Unknown	$5C	16	Unknown
+Unknown	$60	9	Unknown
+Not used	$64	1028	Not used
+Unknown	$80	9	Unknown
+Not used	$84	1028	Not used
+Unknown	$A0	9	Unknown
+Not used	$A4	1028	Not used
+Unknown	$C0	9	Unknown
+Not used	$C4	1028	Not used
+Unknown	$E0	9	Unknown
+Unknown	$E4	9	Unknown
+Unknown	$E8	9	Unknown
+Unknown	$EC	4	Unknown
+Unknown	$F0	4	Unknown
+Not used	$F4	1012	Not used
Index: /oup/structdefs/06-04-24/ONTA.txt
===================================================================
--- /oup/structdefs/06-04-24/ONTA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONTA.txt	(revision 8)
@@ -0,0 +1,8 @@
+Trigger Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1016	Not used
+Packages used	$18	4	Amount of packages that follow
+Packages possible	$1C	4	Amount of packages that are possible
+*Package		$20	$18	4	416
+Unknown	$00	1416	Unknown; never used in Oni
Index: /oup/structdefs/06-04-24/ONVL.txt
===================================================================
--- /oup/structdefs/06-04-24/ONVL.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONVL.txt	(revision 8)
@@ -0,0 +1,7 @@
+Oni Variant List
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+ONCV-link	$00	12	Link to the Character Variant
Index: /oup/structdefs/06-04-24/ONWC.txt
===================================================================
--- /oup/structdefs/06-04-24/ONWC.txt	(revision 8)
+++ /oup/structdefs/06-04-24/ONWC.txt	(revision 8)
@@ -0,0 +1,158 @@
+Oni Weapon Class
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	9	Unknown
+Unknown	$20	9	Unknown
+Unknown	$24	16	Unknown
+TXMP-link	$28	12	Link to the first target texture
+Unknown 	$2C	16	Unknown
+Unknown	$30	9	Unknown
+TXMP-link	$34	12	Link to the second target texture
+Unknown	$38	16	Unknown
+Unknown	$3C	9	Unknown
+TXMP-link	$40	12	Link to the third target texture
+Unknown	$44	16	Unknown
+Unknown	$48	9	Unknown
+Unknown	$4C	4	Unknown
+Unknown	$50	9	Unknown
+TXMP-link	$54	12	Link to the tap_icon texture
+TXMP-link	$58	12	Link to the tap_empty texture
+TXMP-link	$5C	12	Link to the tap_fill texture
+M3GM-link	$60	12	Link to the weapon model
+Weapon name	$64	10032	Name of the weapon
+Unknown	$84	9	Unknown
+Unknown	$88	9	Unknown
+Unknown	$8C	9	Unknown
+Unknown	$90	9	Unknown
+Unknown	$94	9	Unknown
+Unknown	$98	9	Unknown
+Unknown	$9C	9	Unknown
+Unknown	$A0	9	Unknown
+Unknown	$A4	9	Unknown
+Unknown	$A8	9	Unknown
+Unknown	$AC	9	Unknown
+Unknown	$B0	9	Unknown
+Unknown	$B4	9	Unknown
+Unknown	$B8	9	Unknown
+Unknown	$BC	9	Unknown
+Unknown	$C0	2	Unknown; always the same
+Unknown	$C2	2	Unknown
+Unknown	$C4	2	Unknown
+Pause after reload  	$C6	2	Pause after reload in 1/60 seconds
+Shots	$C8	2	Amount of shots
+Packages used	$CA	2	Amount of used packages (the file contains space for 16 packages)
+Shot modes	$CC	2	Number of shot modes
+Pause before reload	$CE	2	Pause before reload in 1/60 seconds
+Unknown	$D0	2	Unknown
+Unknown	$D2	2	Unknown; always zero
+Weapon options 1	$D4	10	Weapon options 1
+Weapon options 2	$D5	10	Weapon options 2
+Weapon options 3	$D6	10	Weapon options 3
+Unknown	$D7	1	Unknown; always the same
+Unknown	$D8	2	Unknown
+Unknown	$DA	2	Unknown; always the same
+Unknown	$DC	9	Unknown
+Unknown	$E0	9	Unknown
+Unknown	$E4	9	Unknown
+Unknown	$E8	9	Unknown
+Unknown	$EC	9	Unknown
+Unknown	$F0	9	Unknown
+Unknown	$F4	9	Unknown
+Unknown	$F8	9	Unknown
+Unknown	$FC	9	Unknown
+Unknown	$100	9	Unknown
+Unknown	$104	9	Unknown
+Unknown	$108	9	Unknown
+Unknown	$10C	9	Unknown
+Unknown	$110	9	Unknown
+Unknown	$114	9	Unknown
+Unknown	$118	9	Unknown
+Unknown	$11C	9	Unknown
+Unknown	$120	9	Unknown
+Range of fire	$124	9	Range of fire
+Unknown	$128	9	Scattering angle ? / slice ?
+Unknown	$12C	9	Unknown; always the same
+Unknown	$130	9	Unknown
+Unknown	$134	9	Unknown
+Unknown	$138	9	Unknown
+Unknown	$13C	2	Unknown; always the same
+Weapon id	$13E	2	Id of the weapon
+Unknown	$140	4	Unknown
+Unknown	$144	9	Unknown
+Unknown	$148	9	Unknown
+Unknown	$14C	9	Unknown
+Unknown	$150	9	Unknown
+Unknown	$154	9	Unknown
+Unknown	$158	9	Unknown; always the same
+Unknown	$15C	9	Unknown; only w11_ba1 use it
+Unknown	$160	9	Unknown; always the same
+Unknown	$164	9	Unknown; always the same
+Unknown	$168	9	Unknown; always the same
+Unknown	$16C	9	Unknown; only w11_ba1 use it
+Unknown	$170	9	Unknown; always the same
+Unknown	$174	9	Unknown; always the same
+Unknown	$178	9	Unknown; always the same
+Unknown	$17C	9	Unknown; only w11_ba1 use it
+Unknown	$180	9	Unknown; always the same
+Unknown	$184	9	Unknown; always the same
+Unknown	$188	9	Unknown; always the same
+Unknown	$18C	9	Unknown; only w11_ba1 use it
+Unknown	$190	9	Unknown; only w11_ba1 use it
+Unknown	$194	9	Unknown; only w11_ba1 use it
+Unknown	$198	9	Unknown; only w11_ba1 use it
+Unknown	$19C	9	Unknown; only w11_ba1 use it
+Unknown	$1A0	9	Unknown; only w11_ba1 use it
+Unknown	$1A4	9	Unknown; only w11_ba1 use it
+Unknown	$1A8	9	Unknown; always the same
+Unknown	$1AC	9	Unknown; only w11_ba1 use it
+Unknown	$1B0	9	Unknown; only w11_ba1 use it
+Unknown	$1B4	9	Unknown; only w11_ba1 use it
+Unknown	$1B8	9	Unknown; always the same
+Unknown	$1BC	2	Unknown; only w11_ba1 use it
+Unknown	$1BE	2	Unknown; only w11_ba1 use it
+Unknown	$1C0	9	Unknown; always the same
+Unknown	$1C4	9	Unknown; only w11_ba1 use it
+Unknown	$1C8	9	Unknown; only w11_ba1 use it
+Unknown	$1CC	9	Unknown; always the same
+Unknown	$1D0	9	Unknown; always the same
+Unknown	$1D4	9	Unknown; always the same
+
+Empty weapon sound	$6D8	132	Reference to an OSBD file
+Unknown	$6F8	4	Unknown
+TXMP-link	$6FC	12	Link to the glow texture
+TXMP-link	$700	12	Link to the glow_ammo texture
+Unknown	$704	9	Unknown
+Unknown	$708	9	Unknown
+Unknown	$70C	9	Unknown
+Unknown	$710	9	Unknown
+Unknown	$714	9	Unknown
+Unknown	$718	9	Unknown
+Not used	$71C	1004	Not used
+
+*Packages		$1D8	$CA	2	64
+Unknown	$00	9	Unknown
+Unknown	$04	9	Unknown
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	9	Unknown
+Unknown	$20	9	Unknown
+Unknown	$24	9	Unknown
+Unknown	$28	9	Unknown
+Unknown	$2C	9	Unknown
+Particle reference	$30	116	Reference to the weapon particle
+Unknown	$40	2	Unknown; always the same
+Unknown	$42	2	Unknown; always the same
+Unknown	$44	2	Unknown
+Shot frequency	$46	2	Shot frequency in 1/60 seconds
+Unknown	$48	2	Unknown
+Unknown	$4A	2	Unknown
+Unknown	$4C	2	Unknown
+Unknown	$4E	2	Unknown
Index: /oup/structdefs/06-04-24/OPge.txt
===================================================================
--- /oup/structdefs/06-04-24/OPge.txt	(revision 8)
+++ /oup/structdefs/06-04-24/OPge.txt	(revision 8)
@@ -0,0 +1,7 @@
+Objective Page
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1002	Not used
+Level	$0A	2	Level
+IGPA-link	$0C	12	Link to the In-Game User Interface Page Array
+Not used	$10	1016	Not used
Index: /oup/structdefs/06-04-24/OSBD.txt
===================================================================
--- /oup/structdefs/06-04-24/OSBD.txt	(revision 8)
+++ /oup/structdefs/06-04-24/OSBD.txt	(revision 8)
@@ -0,0 +1,6 @@
+Oni Sound Binary Data
+File id	$00	12	File id
+Level id	$04	17	Level id
+Size	$08	4	Size of the part in the raw file
+Offset	$0C	11	At this position starts the part in the raw/sep file
+Not used	$10	1016	Not used
Index: /oup/structdefs/06-04-24/OTIT.txt
===================================================================
--- /oup/structdefs/06-04-24/OTIT.txt	(revision 8)
+++ /oup/structdefs/06-04-24/OTIT.txt	(revision 8)
@@ -0,0 +1,22 @@
+Oct Tree Leaf Node Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	32
+1st child pointer	$00	3	Pointer to the 1st child
+High bit	$03	1	High bit
+2nd child pointer	$04	3	Pointer to the 2nd child
+High bit	$07	1	High bit
+3rd child pointer	$08	3	Pointer to the 3rd child
+High bit	$0B	1	High bit
+4th child pointer	$0C	3	Pointer to the 4th child
+High bit	$0F	1	High bit
+5th child pointer	$10	3	Pointer to the 5th child
+High bit	$13	1	High bit
+6th child pointer	$14	3	Pointer to the 6th child
+High bit	$17	1	High bit
+7th child pointer	$18	3	Pointer to the 7th child
+High bit	$1B	1	High bit
+8th child pointer	$1C	3	Pointer to the 8th child
+High bit	$1F	1	High bit
Index: /oup/structdefs/06-04-24/OTLF.txt
===================================================================
--- /oup/structdefs/06-04-24/OTLF.txt	(revision 8)
+++ /oup/structdefs/06-04-24/OTLF.txt	(revision 8)
@@ -0,0 +1,22 @@
+Oct Tree Interior Node Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	36
+Unknown	$00	3	Unknown
+High bit	$03	1	High bit
+Unknown	$04	3	Unknown
+High bit	$07	1	High bit
+Unknown	$08	3	Unknown
+High bit	$0B	1	High bit
+Unknown	$0C	3	Unknown
+High bit	$0F	1	High bit
+Unknown	$10	3	Unknown
+High bit	$13	1	High bit
+Unknown	$14	3	Unknown
+High bit	$17	1	High bit
+Unknown	$18	3	Unknown
+High bit	$1B	1	High bit
+Unknown	$1C	9	Unknown
+Unknown	$20	4	Unknown; always the same (?)
Index: /oup/structdefs/06-04-24/PLEA.txt
===================================================================
--- /oup/structdefs/06-04-24/PLEA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/PLEA.txt	(revision 8)
@@ -0,0 +1,10 @@
+Plane Equation Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	32
+Unknown	$00	9	Unknown
+Unknown	$04	9	Unknown
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
Index: /oup/structdefs/06-04-24/PNTA.txt
===================================================================
--- /oup/structdefs/06-04-24/PNTA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/PNTA.txt	(revision 8)
@@ -0,0 +1,19 @@
+3D Point Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1012	Not used
+Minimum x-coordinate	$14	9	Minimum x-coordinate of all packages below
+Minimum y-coordinate	$18	9	Minimum y-coordinate (height) of all packages below
+Minimum z-coordinate	$1C	9	Minimum z-coordinate of all packages below
+Maximum x-coordinate	$20	9	Maximum x-coordinate of all packages below
+Maximum y-coordinate	$24	9	Maximum y-coordinate (height) of all packages below
+Maximum z-coordinate	$28	9	Maximum z-coordinate of all packages below
+Center x-coordinate	$2C	9	x-coordinate of the center [ (max. x-coord. - min. x-coord.) ÷ 2) + min. x-coord. ]
+Center y-coordinate	$30	9	y-coordinate of the center [ (max. y-coord. - min. y-coord.) ÷ 2) + min. y-coord. ]
+Center z-coordinate	$34	9	z-coordinate of the center [ (max. z-coord. - min. z-coord.) ÷ 2) + min. z-coord. ]
+Distance	$38	9	Distance from the center to each of the both points above
+Packages	$3C	4	Amount of packages that follow
+*Package		$40	$3C	4	12
+x-coordinate	$00	9	x-coordinate of the point
+y-coordinate	$04	9	y-coordinate (height) of the point
+z-coordinate	$08	9	z-coordinate of the point
Index: /oup/structdefs/06-04-24/PSPC.txt
===================================================================
--- /oup/structdefs/06-04-24/PSPC.txt	(revision 8)
+++ /oup/structdefs/06-04-24/PSPC.txt	(revision 8)
@@ -0,0 +1,43 @@
+Particle Specification (coordinates of UI element in texture) (see pspc.png)
+
+ID	$00	12
+LevelID	$04	17
+LFT-LT	$08	2	LT Left
+TOP-LT	$0A	2	LT Top
+LFT-HL	$0C	2	HL Left (rubber)
+TOP-HL	$0E	2	HL Top (rubber)
+LFT-LB	$10	2	LB Left
+TOP-LB	$12	2	LB Top
+LFT-VT	$14	2	VT Left (rubber)
+TOP-VT	$16	2	VT Top (rubber)
+LFT-CC	$18	2	CC Left (rubber)
+TOP-CC	$1A	2	CC Top (rubber)
+LFT-VB	$1C	2	VB Left (rubber)
+TOP-VB	$1E	2	VB Top (rubber)
+LFT-RT	$20	2	RT Left
+TOP-RT	$22	2	RT Top
+LFT-HR	$24	2	HR Left (rubber)
+TOP-HR	$26	2	HR Top (rubber)
+LFT-RB	$28	2	RB Left
+TOP-RB	$2A	2	RB Top
+
+RGH-LT	$2C	2	LT Right
+BTM-LT	$2E	2	LT Bottom
+RGH-HL	$30	2	HL Right (rubber)
+BTM-HL	$32	2	HL Bottom (rubber)
+RGH-LB	$34	2	LB Right
+BTM-LB	$36	2	LB Bottom
+RGH-VT	$38	2	VT Right (rubber)
+BTM-VT	$3A	2	VT Bottom (rubber)
+RGH-CC	$3C	2	CC Right (rubber)
+BTM-CC	$3E	2	CC Bottom (rubber)
+RGH-VB	$40	2	VB Right (rubber)
+BTM-VB	$42	2	VB Bottom (rubber)
+RGH-RT	$44	2	RT Right
+BTM-RT	$46	2	RT Bottom
+RGH-HR	$48	2	HR Right (rubber)
+BTM-HR	$4A	2	HR Bottom (rubber)
+RGH-RB	$4C	2	RB Right
+BTM-RB	$4E	2	RB Bottom
+TXMP-Link	$50	12	Corresponding texture
+
Index: /oup/structdefs/06-04-24/PSUI.txt
===================================================================
--- /oup/structdefs/06-04-24/PSUI.txt	(revision 8)
+++ /oup/structdefs/06-04-24/PSUI.txt	(revision 8)
@@ -0,0 +1,48 @@
+Part Specifications UI (User Interface)
+File id	$00	12	File id
+Level id	$04	17	Level id
+PSpc-link	$08	12	Link to the Part Specification
+PSpc-link	$0C	12	Link to the Part Specification
+PSpc-link	$10	12	Link to the Part Specification
+PSpc-link	$14	12	Link to the Part Specification
+PSpc-link	$18	12	Link to the Part Specification
+PSpc-link	$1C	12	Link to the Part Specification
+PSpc-link	$20	12	Link to the Part Specification
+PSpc-link	$24	12	Link to the Part Specification
+PSpc-link	$28	12	Link to the Part Specification
+PSpc-link	$2C	12	Link to the Part Specification
+PSpc-link	$30	12	Link to the Part Specification
+PSpc-link	$34	12	Link to the Part Specification
+PSpc-link	$38	12	Link to the Part Specification
+PSpc-link	$3C	12	Link to the Part Specification
+PSpc-link	$40	12	Link to the Part Specification
+PSpc-link	$44	12	Link to the Part Specification
+PSpc-link	$48	12	Link to the Part Specification
+PSpc-link	$4C	12	Link to the Part Specification
+PSpc-link	$50	12	Link to the Part Specification
+PSpc-link	$54	12	Link to the Part Specification
+PSpc-link	$58	12	Link to the Part Specification
+PSpc-link	$5C	12	Link to the Part Specification
+PSpc-link	$60	12	Link to the Part Specification
+PSpc-link	$64	12	Link to the Part Specification
+PSpc-link	$68	12	Link to the Part Specification
+PSpc-link	$6C	12	Link to the Part Specification
+PSpc-link	$70	12	Link to the Part Specification
+PSpc-link	$74	12	Link to the Part Specification
+PSpc-link	$78	12	Link to the Part Specification
+PSpc-link	$7C	12	Link to the Part Specification
+PSpc-link	$80	12	Link to the Part Specification
+PSpc-link	$84	12	Link to the Part Specification
+PSpc-link	$88	12	Link to the Part Specification
+PSpc-link	$8C	12	Link to the Part Specification
+PSpc-link	$90	12	Link to the Part Specification
+PSpc-link	$94	12	Link to the Part Specification
+PSpc-link	$98	12	Link to the Part Specification
+PSpc-link	$9C	12	Link to the Part Specification
+PSpc-link	$A0	12	Link to the Part Specification
+PSpc-link	$A4	12	Link to the Part Specification
+PSpc-link	$A8	12	Link to the Part Specification
+PSpc-link	$AC	12	Link to the Part Specification
+PSpc-link	$B0	12	Link to the Part Specification
+PSpc-link	$B4	12	Link to the Part Specification
+Not used	$B8	1008	Not used
Index: /oup/structdefs/06-04-24/PSpL.txt
===================================================================
--- /oup/structdefs/06-04-24/PSpL.txt	(revision 8)
+++ /oup/structdefs/06-04-24/PSpL.txt	(revision 8)
@@ -0,0 +1,8 @@
+Part Specification List
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	8
+Unknown	$00	4	Unknown
+PSpc-link	$04	12	Link to the Part Specification
Index: /oup/structdefs/06-04-24/QTNA.txt
===================================================================
--- /oup/structdefs/06-04-24/QTNA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/QTNA.txt	(revision 8)
@@ -0,0 +1,14 @@
+Quad Tree Node Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	16
+Unknown	$00	3	Unknown
+High bit	$03	1	High bit
+Unknown	$04	3	Unknown
+High bit	$07	1	High bit
+Unknown	$08	3	Unknown
+High bit	$0B	1	High bit
+Unknown	$0C	3	Unknown
+High bit	$0F	1	High bit
Index: /oup/structdefs/06-04-24/SNDD.txt
===================================================================
--- /oup/structdefs/06-04-24/SNDD.txt	(revision 8)
+++ /oup/structdefs/06-04-24/SNDD.txt	(revision 8)
@@ -0,0 +1,8 @@
+Sound Data
+File id	$00	12	File id
+Level id	$04	17	Level id
+Wav header	$08	10054	Wav header; don't alter it
+Duration	$3E	2	Duration in 1/60 seconds
+Size	$40	4	Size of the part in the raw file
+Offset	$44	11	At this position starts the part in the raw file
+Not used	$48	1024	Not used
Index: /oup/structdefs/06-04-24/SUBT.txt
===================================================================
--- /oup/structdefs/06-04-24/SUBT.txt	(revision 8)
+++ /oup/structdefs/06-04-24/SUBT.txt	(revision 8)
@@ -0,0 +1,8 @@
+Subtitles
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1016	Not used
+Raw-Link	$18	11	Address of the subtitle data in the .raw-file
+Packages	$1C	4	Amount of packages that follow
+*Packages		$20	$1C	4	4
+Raw-link	$0	11	Start position of the subtitle in the raw file
Index: /oup/structdefs/06-04-24/StNA.txt
===================================================================
--- /oup/structdefs/06-04-24/StNA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/StNA.txt	(revision 8)
@@ -0,0 +1,7 @@
+String Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	4
+TStr-link	$00	12	Link to the String
Index: /oup/structdefs/06-04-24/TRAC.txt
===================================================================
--- /oup/structdefs/06-04-24/TRAC.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRAC.txt	(revision 8)
@@ -0,0 +1,11 @@
+Animation Collection
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1016	Not used
+TRAC-link	$18	12	Link to a shared Animation Collection
+Unknown	$1C	2	Unknown
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	12
+Unknown	$00	4	Unknown
+Not used	$04	1004	Not used
+TRAM-link	$08	12	Link to the Animation
Index: /oup/structdefs/06-04-24/TRAM.txt
===================================================================
--- /oup/structdefs/06-04-24/TRAM.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRAM.txt	(revision 8)
@@ -0,0 +1,126 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+File id	$00	12	File id
+Level id	$04	17	Level id
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags	$3C	4	Flags; it seems that Oni read it as 4 byte string from left to right; I would read it as 4 seperate bitsets
+TRAM link	$40	4	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	4	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	4	Used parts; used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	4	Replace parts; used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	14	Attack voice sound (f.e. Konokos "Rising fury!")
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	116	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	14	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
+
+
+*Unknown
+Unknown	$08	4	Unknown; always zero
+Unknown	$58	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$5C	9	Unknown; always 1,000,000,000 if the attack part doesn't exist
+Unknown	$60	9	Unknown; always -1,000,000,000 if the attack part doesn't exist
+Unknown	$64	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$68	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$6C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$70	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$74	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$78	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$7C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$80	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$84	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$88	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$8C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$90	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$94	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$98	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$9C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$AC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$BC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$CC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$DC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$EC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$F0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$F4	14	Unknown; always -1 if the attack part doesn't exist
+Unknown	$F6	2	Unknown; always zero
+Unknown	$F8	9	Unknown
+Unknown	$FC	9	Unknown
+Unknown	$100	9	Unknown
+Unknown	$104	9	Unknown
+Unknown	$108	9	Unknown
+Unknown	$10C	9	Unknown
+Unknown	$110	9	Unknown
+Unknown	$114	14	Unknown
+Unknown	$116	1	Unknown
+Unknown	$117	1	Unknown
+Unknown	$118	9	Unknown
+Unknown	$11C	9	Unknown
+Unknown	$120	9	Unknown
+Unknown	$124	9	Unknown
+Unknown	$128	9	Unknown
+Unknown	$12C	9	Unknown
+Unknown	$130	9	Unknown
+Unknown	$134	8	Unknown; always zero
+Unknown	$154	2	Unknown; it seems that it belongs to the sound part
+Unknown	$156	2	Unknown
+Unknown	$158	2	Unknown
+Unknown	$15A	2	Unknown
+Unknown	$15C	2	Unknown
+Unknown	$180	1	Unknown
+Unknown	$181	1	Unknown
+
+
+*Unused
+Not used	$188	10024	Not used
+
Index: /oup/structdefs/06-04-24/TRAM_2.txt
===================================================================
--- /oup/structdefs/06-04-24/TRAM_2.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRAM_2.txt	(revision 8)
@@ -0,0 +1,122 @@
+Totoro Animation Sequence (Totoro is the name of the character animation engine.)
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	4	Unknown; always zero
+Raw link	$0C	11	Address of the y-position data in the .raw-file
+Raw link	$10	11	Address of the x-z-position data in the .raw-file
+Raw link	$14	11	Address of the attack data in the .raw-file
+Raw link	$18	11	Address of the damage data in the .raw-file
+Raw link	$1C	11	Address of the motion blur data in the .raw-file
+Raw link	$20	11	Address of the shortcut data in the .raw-file
+Raw link	$24	11	Address of the throw data in the .raw-file
+Raw link	$28	11	Address of the footstep data in the .raw-file
+Raw link	$2C	11	Address of the particle data in the .raw-file
+Raw link	$30	11	Address of the position data in the .raw-file
+Raw link	$34	11	Address of the bodypart animation data in the .raw-file
+Raw link	$38	11	Address of the sound data in the .raw-file
+Flags 1	$3C	10	Flags 1 in connection to the anim_flags.StNA file
+Flags 2	$3D	10	Flags 2 in connection to the anim_flags.StNA file
+Flags 3	$3E	10	Flags 3 in connection to the anim_flags.StNA file
+Unknown	$3F	1	Unknown; always the same
+TRAM link	$40	12	First direct animation link; this animation follows after a left mouse click (punch)
+TRAM link	$44	12	Second direct animation link; this animation follows after a right mouse click (kick)
+Used parts	$48	4	Used parts; used for weapon animations like recoil, reload, draw weapon, etc.
+Replace parts	$4C	4	Replace parts; used for weapon animations like recoil, reload, draw weapon, etc.
+Final rotation	$50	9	Final rotation; stored as multiples of the number "pi" (3.141592...)
+Move direction	$54	2	Move direction
+Attack voice sound	$56	14	Attack voice sound (f.e. Konokos "Rising fury!")
+Unknown	$58	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$5C	9	Unknown; always 1,000,000,000 if the attack part doesn't exist
+Unknown	$60	9	Unknown; always -1,000,000,000 if the attack part doesn't exist
+Unknown	$64	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$68	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$6C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$70	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$74	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$78	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$7C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$80	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$84	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$88	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$8C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$90	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$94	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$98	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$9C	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$A8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$AC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$B8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$BC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$C8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$CC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$D8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$DC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E4	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$E8	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$EC	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$F0	9	Unknown; always zero if the attack part doesn't exist
+Unknown	$F4	14	Unknown; always -1 if the attack part doesn't exist
+Unknown	$F6	2	Unknown; always zero
+Unknown	$F8	9	Unknown
+Unknown	$FC	9	Unknown
+Unknown	$100	9	Unknown
+Unknown	$104	9	Unknown
+Unknown	$108	9	Unknown
+Unknown	$10C	9	Unknown
+Unknown	$110	9	Unknown
+Unknown	$114	14	Unknown
+Unknown	$116	1	Unknown
+Unknown	$117	1	Unknown
+Unknown	$118	9	Unknown
+Unknown	$11C	9	Unknown
+Unknown	$120	9	Unknown
+Unknown	$124	9	Unknown
+Unknown	$128	9	Unknown
+Unknown	$12C	9	Unknown
+Unknown	$130	9	Unknown
+Unknown	$134	8	Unknown; always zero
+Extent packages	$138	4	Amount of packages of the extent data
+Raw link	$13C	11	Address of the extent data in the .raw-file
+Attack sound	$140	116	Reference to an attack sound (f.e. "slap") of level 0
+Hard pause	$150	2	Hard pause in 1/60 seconds
+Soft pause	$152	2	Soft pause in 1/60 seconds
+Unknown	$154	2	Unknown; it seems that it belongs to the sound part
+Unknown	$156	2	Unknown
+Unknown	$158	2	Unknown
+Unknown	$15A	2	Unknown
+Unknown	$15C	2	Unknown
+Frames	$15E	2	Frames per second
+Compression	$160	2	Compression size
+Type	$162	2	ID for the animation of the opponent
+Animation Type	$164	2	ID for the animation of the opponent
+From state	$166	2	From state
+To state	$168	2	To state
+Bodyparts	$16A	2	Amount of bodyparts
+Frames	$16C	2	Animation length in frames
+Duration	$16E	2	Duration of the animation in frames
+Varient	$170	2	Varient; It seems that Oni read it as 2 byte string from left to right; I would read it as 2 seperate bitsets or as a short
+Varient end	$172	2	Varient end; It seems that Oni read it as 2 byte string from left to right; I would read it as a short
+Atomic start	$174	2	Atomic start
+Atomic end	$176	2	Atomic end
+End interpolation	$178	2	End interpolation
+Maximal interpolation	$17A	2	Maximal interpolation
+Action frame	$17C	14	Action frame; at this frame starts the "real" animation
+First level	$17E	2	First level; the level where you can use this animation the first time
+Unknown	$180	1	Unknown
+Unknown	$181	1	Unknown
+Attack packages	$182	1	Amount of packages of the attack data
+Damage packages	$183	1	Amount of packages of the damage data
+Motion blur packages	$184	1	Amount of packages of the motion blur data
+Shortcut packages	$185	1	Amount of packages of the shortcut data
+Footstep packages	$186	1	Amount of packages of the footstep data
+Particle packages	$187	1	Amount of packages of the particle data
+Not used	$188	10024	Not used
Index: /oup/structdefs/06-04-24/TRAS.txt
===================================================================
--- /oup/structdefs/06-04-24/TRAS.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRAS.txt	(revision 8)
@@ -0,0 +1,13 @@
+Totoro Aiming Screen
+File id	$00	12	File id
+Level id	$04	17	Level id
+TRAM-link	$08	12	Link to the Aiming Animation
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	2	Unknown
+Unknown	$16	2	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	9	Unknown
+Unknown	$20	2	Unknown
+Unknown	$22	2	Unknown
+Not used	$24	1028	Not used
Index: /oup/structdefs/06-04-24/TRBS.txt
===================================================================
--- /oup/structdefs/06-04-24/TRBS.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRBS.txt	(revision 8)
@@ -0,0 +1,10 @@
+Totoro Body Set
+File id	$00	12	File id
+Level id	$04	17	Level id
+TRCM-link	$08	12	Link to the extra low detailed body array
+TRCM-link	$0C	12	Link to the low detailed body array
+TRCM-link	$10	12	Link to the medium detailed body array
+TRCM-link	$14	12	Link to the high detailed body array
+TRCM-link	$18	12	Link to the extra high detailed body array
+Not used	$1C	1004	Not used
+
Index: /oup/structdefs/06-04-24/TRCM.txt
===================================================================
--- /oup/structdefs/06-04-24/TRCM.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRCM.txt	(revision 8)
@@ -0,0 +1,15 @@
+Totoro Quaternion Body
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	4	Unknown
+Bodyparts	$0C	2	Number of bodyparts
+Not used	$0E	1002	Not used
+Internal file name	$10	10064	Internal file name
+Not used	$50	1004	Old offset link; you can set it to zero if you want
+Not used	$54	1004	Old offset link; you can set it to zero if you want
+Not used	$58	1004	Old offset link; you can set it to zero if you want
+TRGA-link	$5C	12	Link to the Body Geometry Array
+TRTA-link	$60	12	Link to the Body Translation Array
+TRIA-link	$64	12	Link to the Body Index Array
+Not used	$68	1024	Not used
+
Index: /oup/structdefs/06-04-24/TRGA.txt
===================================================================
--- /oup/structdefs/06-04-24/TRGA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRGA.txt	(revision 8)
@@ -0,0 +1,8 @@
+Totoro Quaternion Body Geometry Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	4
+M3GM-link	$00	12	Link to the body geometry
+
Index: /oup/structdefs/06-04-24/TRGE.txt
===================================================================
--- /oup/structdefs/06-04-24/TRGE.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRGE.txt	(revision 8)
@@ -0,0 +1,13 @@
+Trigger Emitter
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	9	Unknown
+Unknown	$0C	9	Unknown
+Unknown	$10	9	Unknown
+Unknown	$14	9	Unknown
+Unknown	$18	9	Unknown
+Unknown	$1C	9	Unknown
+M3GM-link	$20	12	Link to the Geometry
+Unknown	$24	4	Unknown; maybe a canceled link
+Not used	$28	1024	Not used
+
Index: /oup/structdefs/06-04-24/TRIA.txt
===================================================================
--- /oup/structdefs/06-04-24/TRIA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRIA.txt	(revision 8)
@@ -0,0 +1,10 @@
+Totoro Quaternion Body Translation Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	4
+Not used	$00	1001	Oni doesn't need it; you can set it to what you want
+Major joint	$01	1	Major joint
+Minor joint	$02	1	Minor joint
+Not used	$03	1001	Not used
Index: /oup/structdefs/06-04-24/TRIG.txt
===================================================================
--- /oup/structdefs/06-04-24/TRIG.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRIG.txt	(revision 8)
@@ -0,0 +1,19 @@
+Trigger
+File id	$00	12	File id
+Level id	$04	17	Level id
+Unknown	$08	16	Unknown; always the same
+Unknown	$0C	4	Unknown; always the same
+Unknown	$10	4	Unknown; always the same
+Unknown	$14	9	Unknown; always the same
+M3GM-link	$18	12	Link to the Geometry
+Unknown	$1C	4	Unknown; always the same
+Unknown	$20	2	Unknown
+Unknown	$22	2	Unknown
+TRGE-link	$24	12	Link to the Trigger Emitter
+OBAN-link	$28	12	Link to the Object Animation
+Trigger active sound	$2C	132	Reference to an OSBD file
+Trigger hit sound	$4C	132	Reference to an OSBD file
+Unknown	$6C	4	Unknown; always the same
+Unknown	$70	4	Unknown; always the same
+Not used	$74	1012	Not used
+
Index: /oup/structdefs/06-04-24/TRMA.txt
===================================================================
--- /oup/structdefs/06-04-24/TRMA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRMA.txt	(revision 8)
@@ -0,0 +1,8 @@
+Texture Map Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	4
+TXMP-link	$00	12	Link to the Texture
+
Index: /oup/structdefs/06-04-24/TRSC.txt
===================================================================
--- /oup/structdefs/06-04-24/TRSC.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRSC.txt	(revision 8)
@@ -0,0 +1,8 @@
+Screen (Aiming) Collection
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	4
+TRAS-link	$00	12	Link to the Aiming Screen
+
Index: /oup/structdefs/06-04-24/TRTA.txt
===================================================================
--- /oup/structdefs/06-04-24/TRTA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TRTA.txt	(revision 8)
@@ -0,0 +1,9 @@
+Totoro Quaternion Body Translation Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1022	Not used
+Packages	$1E	2	Amount of packages that follow
+*Package		$20	$1E	2	12
+x-position	$00	9	x-postition of the bodypart in connection to the TRIA file
+y-position	$04	9	y-postition of the bodypart in connection to the TRIA file
+z-position	$08	9	z-postition of the bodypart in connection to the TRIA file
Index: /oup/structdefs/06-04-24/TSFF.txt
===================================================================
--- /oup/structdefs/06-04-24/TSFF.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TSFF.txt	(revision 8)
@@ -0,0 +1,9 @@
+Font Family
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1016	Not used
+TSFL-link	$18	12	Link to the Font Language
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+TRAS-link	$00	12	Link to the Font
+
Index: /oup/structdefs/06-04-24/TSFL.txt
===================================================================
--- /oup/structdefs/06-04-24/TSFL.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TSFL.txt	(revision 8)
@@ -0,0 +1,9 @@
+Font Language
+File id	$00	12	File id
+Level id	$04	17	Level id
+Char block 1	$08	10064	Char block 1
+Char block 2	$48	10064	Char block 2
+Char block 3	$88	10064	Char block 3
+Char block 4	$C8	10064	Char block 4
+Char block 5	$108	10064	Char block 5
+Not used	$148	1024	Not used
Index: /oup/structdefs/06-04-24/TSFT.txt
===================================================================
--- /oup/structdefs/06-04-24/TSFT.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TSFT.txt	(revision 8)
@@ -0,0 +1,15 @@
+Font
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1006	Not used
+Unknown	$0E	2	Unknown
+Unknown	$10	4	Unknown
+Unknown	$14	2	Unknown
+Unknown	$16	2	Unknown
+Unknown	$18	2	Unknown
+Unknown	$1A	2	Unknown
+TSGA-link	$1C	12	Link to the Glyph Array
+Not used	$20	2020	Not used
+Packages	$41C	4	Amount of packages that follow
+*Package		$420	$41C	4	4
+Unknown	$00	8	Unknown
Index: /oup/structdefs/06-04-24/TSGA.txt
===================================================================
--- /oup/structdefs/06-04-24/TSGA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TSGA.txt	(revision 8)
@@ -0,0 +1,13 @@
+Glyph Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+*Package		$08	$04	$100	20
+Unknown	$00	2	Unknown
+Unknown	$02	2	Unknown
+Unknown	$04	2	Unknown
+Unknown	$06	2	Unknown
+Unknown	$08	2	Unknown
+Unknown	$0A	2	Unknown
+Unknown	$0C	2	Unknown
+Unknown	$0E	2	Unknown
+Unknown	$10	4	Unknown
Index: /oup/structdefs/06-04-24/TStr.txt
===================================================================
--- /oup/structdefs/06-04-24/TStr.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TStr.txt	(revision 8)
@@ -0,0 +1,5 @@
+String
+File id	$00	12	File id
+Level id	$04	17	Level id
+Animation string	$08	10128	Animation string
+Not used	$88	1024	Not used
Index: /oup/structdefs/06-04-24/TURR.txt
===================================================================
--- /oup/structdefs/06-04-24/TURR.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TURR.txt	(revision 8)
@@ -0,0 +1,98 @@
+Turret
+File id	$00	12	File id
+Level id	$04	17	Level id
+Turret name	$08	10064	Name of the turret
+Unknown	$48	4	Unknown; always the same
+Not used	$4C	1008	Not used
+Unknown	$54	2	Unknown; always the same
+Packages used	$56	2	Amount of used packages (the file contains space for 16 packages)
+Unknown	$58	2	Unknown; always the same
+Not used	$5A	1006	Not used
+M3GM-link	$60	12	Link to the Geometry
+Unknown	$64	4	Unknown; always the same; maybe a canceled link
+Unknown	$68	4	Unknown; always the same; maybe a canceled link
+M3GM-link	$6C	12	Link to the Geometry
+Unknown	$70	4	Unknown; always the same; maybe a canceled link
+M3GM-link	$74	12	Link to the Geometry
+Unknown	$78	4	Unknown; always the same; maybe a canceled link
+Unknown	$7C	9	Unknown; always the same if it's a floor turret
+Unknown	$80	9	Unknown; always the same if it's a floor turret
+Unknown	$84	9	Unknown; always the same if it's a floor turret
+Unknown	$88	9	Unknown; always the same
+Unknown	$8C	9	Unknown; always the same
+Unknown	$90	9	Unknown; always the same
+*Packages		$94	$56	2	76
+Particle reference	$00	116	Reference to the weapon particle
+Unknown	$10	4	Unknown; always the same
+Shot frequency	$14	4	Shot frequency in 1/60 seconds
+Unknown	$18	9	Unknown
+Unknown	$1C	9	Unknown
+Unknown	$20	9	Unknown
+Unknown	$24	9	Unknown
+Unknown	$28	9	Unknown
+Unknown	$2C	9	Unknown
+Unknown	$30	9	Unknown
+Unknown	$34	9	Unknown
+Unknown	$38	9	Unknown
+Unknown	$3C	9	Unknown
+Unknown	$40	9	Unknown
+Unknown	$44	9	Unknown
+Not used	$48	1004	Not used; always the same
+
+// oup stops here, because it can't read entries after the end of a package block; hope that Alloc will fix that
+
+Unknown	$554	4	Unknown
+Unknown	$558	9	Unknown
+Unknown	$55C	9	Unknown
+Unknown	$560	9	Unknown
+Unknown	$564	9	Unknown
+Unknown	$568	9	Unknown
+Unknown	$56C	9	Unknown
+Unknown	$570	9	Unknown
+Unknown	$574	9	Unknown
+Unknown	$578	9	Unknown
+Unknown	$57C	4	Unknown; always the same
+Unknown	$580	4	Unknown; always the same
+Unknown	$584	4	Unknown; always the same
+Unknown	$588	9	Unknown
+Unknown	$58C	9	Unknown
+Unknown	$590	9	Unknown
+Unknown	$594	9	Unknown
+Unknown	$598	9	Unknown
+Unknown	$59C	9	Unknown
+Unknown	$5A0	9	Unknown; always the same
+Unknown	$5A4	9	Unknown; always the same
+Unknown	$5A8	9	Unknown; always the same
+Unknown	$5AC	9	Unknown; always the same
+Unknown	$5B0	9	Unknown; always the same
+Unknown	$5B4	9	Unknown; always the same
+Unknown	$5B8	4	Unknown; always the same
+Unknown	$5BC	4	Unknown; always the same
+Unknown	$5C0	4	Unknown; always the same
+Unknown	$5C4	4	Unknown; always the same
+Unknown	$5C8	4	Unknown; always the same
+Unknown	$5CC	9	Unknown; always the same
+Unknown	$5D0	9	Unknown; always the same
+Unknown	$5D4	9	Unknown; always the same
+Unknown	$5D8	9	Unknown; always the same
+Unknown	$5DC	9	Unknown; always the same
+Unknown	$5E0	9	Unknown; always the same
+Unknown	$5E4	4	Unknown; always the same
+Unknown	$5E8	4	Unknown; always the same
+Unknown	$5EC	4	Unknown; always the same
+Unknown	$5F0	9	Unknown; always the same
+Unknown	$5F4	9	Unknown; always the same
+Unknown	$5F8	9	Unknown; always the same
+Unknown	$5FC	9	Unknown; always the same
+Unknown	$600	9	Unknown; always the same
+Unknown	$604	9	Unknown; always the same
+Unknown	$608	4	Unknown; always the same
+Unknown	$60C	9	Unknown; always the same if it's a floor turret
+Unknown	$610	9	Unknown; always the same if it's a floor turret
+Unknown	$614	9	Unknown; always the same if it's a floor turret
+Unknown	$618	9	Unknown; always the same if it's a floor turret
+Unknown	$61C	9	Unknown
+Unknown	$620	9	Unknown
+Active turret sound	$624	132	Reference to an OSBD file
+Unknown	$644	10016	Unknown; always the same
+Not used	$654	1012	Not used
Index: /oup/structdefs/06-04-24/TXAN.txt
===================================================================
--- /oup/structdefs/06-04-24/TXAN.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TXAN.txt	(revision 8)
@@ -0,0 +1,11 @@
+Texture Animation
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1012	Not used
+Loop speed	$14	2	Loop speed
+Unknown	$16	2	Unknown
+Unknown	$18	2	Unknown
+Not used	$1A	1002	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+TXMP link	$00	12	Image which is used for the texture animation
Index: /oup/structdefs/06-04-24/TXCA.txt
===================================================================
--- /oup/structdefs/06-04-24/TXCA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TXCA.txt	(revision 8)
@@ -0,0 +1,8 @@
+Texture Coordinate Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	8
+x-coordinate	$00	9	x-coordinate
+y-coordinate	$04	9	y-coordinate
Index: /oup/structdefs/06-04-24/TXMA.txt
===================================================================
--- /oup/structdefs/06-04-24/TXMA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TXMA.txt	(revision 8)
@@ -0,0 +1,7 @@
+Texture Map Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+TXMP-link	$00	12	Link to the Texture
Index: /oup/structdefs/06-04-24/TXMB.txt
===================================================================
--- /oup/structdefs/06-04-24/TXMB.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TXMB.txt	(revision 8)
@@ -0,0 +1,13 @@
+Texture Map Big
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1008	Not used
+Width	$10	2	Width of the complete texture
+Height	$12	2	Height of the complete texture
+Unknown	$14	4	Unknown; all to zero or FF works too
+Unknown	$18	2	Unknown; maybe the number of columns; all to zero or FF works too
+Unknown	$1A	2	Unknown; maybe the number of rows; all to zero or FF works too
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	4
+TXMP-link	$00	12	Link to the Texture
+
Index: /oup/structdefs/06-04-24/TXMP.txt
===================================================================
--- /oup/structdefs/06-04-24/TXMP.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TXMP.txt	(revision 8)
@@ -0,0 +1,15 @@
+Texture
+ID	$00	12	ID of this file
+LevelID	$04	17	ID of the level this file is in
+FileName	$08	10128	Name of the texture
+MIP Mapping	$88	10	MIP Mapping Bitset
+Depth	$89	10	Depth-Bitset
+Unknown	$8A	2	Unknown; always zero
+Width	$8C	2	x-resolution of image
+Height	$8E	2	y-resolution of image
+Storetype	$90	10	Storetype-Bitset
+TXAN-Link	$94	12	Link to the TXAN-file; only used if the texture is the first image of an texture animation
+TXMP-Link	$98	12	Link to another TXMP-file; only used in connection with shade vertex effects
+Raw-Link	$9C	11	Address of the image data in the .raw-file (only for PC-dat-files)
+Raw-Link	$A0	11	Address of the image data in the .raw-file (only for MAC-dat-files)
+Not used	$A4	1028	Not used
Index: /oup/structdefs/06-04-24/TxtC.txt
===================================================================
--- /oup/structdefs/06-04-24/TxtC.txt	(revision 8)
+++ /oup/structdefs/06-04-24/TxtC.txt	(revision 8)
@@ -0,0 +1,5 @@
+Text Console
+File id	$00	12	File id
+Level id	$04	17	Level id
+IGPA-link	$08	12	Link to the In-Game User Interface Page Array
+Not used	$0C	1020	Not used
Index: /oup/structdefs/06-04-24/VCRA.txt
===================================================================
--- /oup/structdefs/06-04-24/VCRA.txt	(revision 8)
+++ /oup/structdefs/06-04-24/VCRA.txt	(revision 8)
@@ -0,0 +1,9 @@
+3D Vector Array
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1018	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	12
+x-coordinate	$00	9	x-coordinate of the vector
+y-coordinate	$04	9	y-coordinate (height) of the vector
+z-coordinate	$08	9	z-coordinate of the vector
Index: /oup/structdefs/06-04-24/WMCL.txt
===================================================================
--- /oup/structdefs/06-04-24/WMCL.txt	(revision 8)
+++ /oup/structdefs/06-04-24/WMCL.txt	(revision 8)
@@ -0,0 +1,8 @@
+WM (Window Menu) Cursor List
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1020	Not used
+Packages	$1C	4	Amount of packages that follow
+*Package		$20	$1C	4	8
+Unknown	$00	4	Unknown; do not change it, Oni won't start if you do that
+PSpc-link	$04	12	Link to the Part Specification
Index: /oup/structdefs/06-04-24/WMDD.txt
===================================================================
--- /oup/structdefs/06-04-24/WMDD.txt	(revision 8)
+++ /oup/structdefs/06-04-24/WMDD.txt	(revision 8)
@@ -0,0 +1,33 @@
+Window Menu Dialog Data
+File id	$00	12	File id
+Level id	$04	4	Level id
+Window title	$08	10256	Title of the main-window
+Window id	$108	4	Id of the main-window
+Window status	$10C	4	Status of the main-window
+Window design	$110	2	Design of the main-window
+Window position	$112	6	Position of the main-window
+Unknown	$114	4	Unknown; always the same
+Width	$118	2	x-dimension of the main-window
+Height	$11A	2	y-dimension of the main-window
+Packages	$11C	4	Amount of packages that follow
+
+*Package		$120	$11C	4	292
+Caption	$0	10256	Caption of the sub-window
+Type	$100	2	Type
+Target id	$102	2	Id of the target
+Option	$104	2	Option
+Unknown	$106	2	Unknown
+Window design	$108	2	Design of the sub-window
+Visible option	$10A	2	Visible option of the sub-window
+x-position	$10C	2	x-position of the sub-window (from the upper left corner of the main-window)
+y-position	$10E	2	y-position of the sub-window (from the upper left corner of the main-window)
+Width	$110	2	x-dimension of the sub-window
+Height	$112	2	y-dimension of the sub-window
+TSFF-link	$114	12	Link to the Font Family
+Font option	$118	4	Font option
+Font color B	$11C	1	Font color - blue part
+Font color G	$11D	1	Font color - green part
+Font color R	$11E	1	Font color - red part
+Unknown	$11F	1	Unknown
+Unknown	$120	2	Unknown; always the same
+Font size	$122	2	Font size
Index: /oup/structdefs/06-04-24/WMMB.txt
===================================================================
--- /oup/structdefs/06-04-24/WMMB.txt	(revision 8)
+++ /oup/structdefs/06-04-24/WMMB.txt	(revision 8)
@@ -0,0 +1,9 @@
+WM (Window Menu) Menu Bar
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1018	Not used
+Unknown	$1A	2	Unknown
+Packages	$1C	4	Amount of packages that follow
+
+*Package		$20	$1C	4	4
+WMM_-link	$00	12	Link to the Window Menu
Index: /oup/structdefs/06-04-24/WMM_.txt
===================================================================
--- /oup/structdefs/06-04-24/WMM_.txt	(revision 8)
+++ /oup/structdefs/06-04-24/WMM_.txt	(revision 8)
@@ -0,0 +1,12 @@
+WM (Window Menu) Menu
+File id	$00	12	File id
+Level id	$04	17	Level id
+Not used	$08	1018	Not used
+Unknown	$1A	2	Unknown
+Menu name	$1C	10064	Name of the menu
+Packages	$5C	4	Amount of packages that follow
+
+*Package		$60	$5C	4	68
+Menu type	$00	2	Type of the menu
+Return number	$02	2	Number that returns if you choose this menu point
+Menu entry	$04	10064	Entry of the menu
Index: /oup/structdefs/06-04-24/WPge.txt
===================================================================
--- /oup/structdefs/06-04-24/WPge.txt	(revision 8)
+++ /oup/structdefs/06-04-24/WPge.txt	(revision 8)
@@ -0,0 +1,6 @@
+Weapon Page
+File id	$00	12	File id
+Level id	$04	17	Level id
+ONWC-link	$08	12	Link to the Oni Weapon Class
+IGPG-link	$0C	12	Link to the In-Game User Interface Page
+Not used	$10	1016	Not used
